AIエージェント組み込みアプリの設計思想:ValuScopeに学ぶ「自動化しすぎない」境界設計
バージョン注記: 2026年7月12日時点の
valuscope-next
の仕様、ソースコード、Git履歴(2026年4月18日〜7月12日、94コミット、266追跡ファイル)を確認して執筆しています。未公開の運用実績を推測せず、実装から確認できる設計と、今後測定すべき効果を分けて扱います。
私はCVCで投資案件を進めるなかで、AIに期待するほど「誰が最後に決めたのか」が曖昧になる怖さも感じてきました。ValuScopeを作って一番考えたのはモデルの賢さではなく、AIをどこで止め、人に判断を返すかです。
最初に、設計の結論を短く置きます。
| テーマ | ValuScopeで採った考え方 |
|---|
| AIの役割 | 調査・整理・提案・成果物生成まで。投資判断そのものは代行しない |
| 人の役割 | 出力を確認し、承認・却下・再実行を選ぶ |
| 自動化の単位 | 1体の万能AIではなく、責務が異なる6種類のエージェント |
| 状態管理 | 実行状態と判断状態を別モデルで記録する |
| 機密境界 | Web検索用の公開情報と、資料・ファンド情報を使う内部分析を分離する |
| 連鎖実行 | 承認されたときだけ、前方のステージへ進み、次工程を起動する |
これは派手な「完全自動投資AI」ではありません。しかし実務では、この控えめさが信頼性の土台になると私は見ています。
AIアプリというと、まずチャット画面を作りたくなります。私も最初はそうでしたが、投資実務を分解すると、中心にあるのは会話ではなく状態です。
ValuScopeが扱うディールは
SOURCED → SCREENING → DD → IC → CLOSED / MONITORING / PASSED
と進みます。その途中で必要な仕事も、Web調査、ピッチ資料分析、面談準備、DD質問、投資委員会付議と変わります。そこで現行実装は、次の6種類へ責務を分けています。
| エージェント | 主な入力 | 主な出力 | 人が見るポイント |
|---|
| Pipeline ToDo | 全ディールの状態 | 優先順位付きToDo | いま誰が何を確認すべきか |
| Web Research | 公開企業情報 | 出典付き調査 | 自称と第三者情報が分かれているか |
| Deck Analysis | 保存資料 | 投資仮説・不足情報 | 資料にない推測が混ざっていないか |
| Meeting Agenda | 資料・履歴 | 面談論点と質問 | 前進/見送りの判別に効くか |
| Question List | 資料・面談メモ | DD質問20〜30問 | 回答で判断がどう変わるか |
| IC Proposal | 資料・参考情報 | 付議骨子 | リスク、反証条件、未確認事項 |
ここでの発見は、エージェントの定義がモデル名ではなく、業務上の責務、入力範囲、成果物、次の判断で決まることです。モデルは交換できますが、責務の境界が曖昧だと、どれほど高性能なモデルでも仕事がにじみます。
開発履歴にもこの順序が表れています。2026年4月19日の初期アプリはポートフォリオ、バリュエーション、資料分析が中心でした。5月31日にディール詳細とAIサブエージェント、6月4日にファンド情報と類似企業調査、7月12日に受信箱と承認フローが大きく統合されています。つまり、先に業務データと計算基盤があり、その後にAI、最後に人間との制御面が追加されました。私はこの順番が重要だったと思います。
最も効いた設計は、AIジョブが成功したことと、人が内容を承認したことを同じ
status
に押し込まなかった点です。
ValuScopeには、AIの処理記録である
DealAgentRun
と、人の判断単位である
ActionItem
があります。前者は
GENERATING / SUCCEEDED / FAILED
、後者は
RUNNING / AWAITING_REVIEW / APPROVED / REJECTED / FAILED / SUPERSEDED / DISMISSED
を持ちます。
| 状態の種類 | 答える問い | 代表的な状態 |
|---|
| 実行状態 | AI処理は技術的に完了したか | GENERATING , SUCCEEDED , FAILED |
| 判断状態 | 人は成果物をどう扱ったか | AWAITING_REVIEW , APPROVED , REJECTED |
| 系譜状態 | 古い依頼との関係は何か | SUPERSEDED |
AIが正常に文章を返しても、その内容が投資判断に使えるとは限りません。逆に、内容が却下されてもジョブ自体は正常終了しています。この二つを分けないと、障害分析と業務監査の両方が壊れます。
承認後の遷移も、プロンプトの文章ではなく純粋関数として固定しています。要点を抜き出すと次の形です。
type Plan = {
proposedStatus: 'SCREENING' | 'DD' | 'IC' | null;
nextAgentTypes: string[];
};
function nextOnApprove(
agentType: string,
currentStage: string,
hasDocs: boolean
): Plan {
const plan =
agentType === 'WEB_RESEARCH'
? {
proposedStatus: 'SCREENING' as const,
nextAgentTypes: hasDocs ? ['DECK_ANALYSIS'] : ['MEETING_AGENDA'],
}
: agentType === 'DECK_ANALYSIS' || agentType === 'MEETING_AGENDA'
? { proposedStatus: 'DD' as const, nextAgentTypes: ['QUESTION_LIST'] }
: agentType === 'QUESTION_LIST'
? { proposedStatus: 'IC' as const, nextAgentTypes: ['IC_PROPOSAL'] }
: { proposedStatus: null, nextAgentTypes: [] };
return isForwardStage(currentStage, plan.proposedStatus)
? plan
: { ...plan, proposedStatus: null };
}
このコードが守るのは二つです。第一に、AI出力だけで勝手に次へ進まないこと。第二に、承認してもステージを後退させないことです。投資実務では例外もありますが、例外を通常フローへ混ぜず、手動判断として扱う方が履歴を読みやすくできます。
チャットAIにも同じ思想を適用しています。ユーザーが「A社のステージをDDにして」と頼んだとき、AIが直接DBを更新するのではなく、変更提案を構造化データで返します。UIは現在値と新しい値を差分表示し、利用者が選択した項目だけを適用します。
ここで面白かったのは、Human-in-the-loopを「確認ダイアログを1枚出すこと」と考えると足りない点です。確認時点から適用時点までに、別のメンバーが値を変えるかもしれません。そのため適用処理はDBの現在値を取り直し、提案時の
currentValue
と一致しない項目を競合としてスキップします。
設計上の責任分解は次のようになります。
- AIは編集可能なホワイトリスト内で変更案を作る。
- JSON Schemaで出力形を固定する。
- UIが現在値と新値を見せる。
- 人が適用対象を選ぶ。
- サーバーが認証、型、enum、必須項目を再検証する。
- DB最新値との競合がない項目だけ更新する。
AIの自由度を下げる設計に見えますが、私は逆だと考えています。書き込み権限を狭くするほど、ユーザーは安心してAIへ広い相談を投げられます。
機密性の設計では、暗号化だけでなく「何を外へ送るか」の境界が重要です。ValuScopeの
WEB_RESEARCH
はWeb検索を使う一方、保存資料やファンドプロファイルを入力にしません。ほかの資料分析系エージェントは保存資料やファンド方針を参照しますが、Web検索を使いません。
この分離には明確な意味があります。
| 経路 | 利用する情報 | 外部ツール | 主なリスク |
|---|
| 公開情報調査 | 企業名、Webサイト、業界、公開説明 | Web search + OpenAI API | 検索語への機密混入 |
| 内部資料分析 | ピッチ資料、面談メモ、ファンド方針 | OpenAI API | 提供権限、保持方針、個人情報 |
| 決定・更新 | 承認結果、ステージ、履歴 | AppSync / DB | 誤更新、競合、権限越境 |
UIでも
web-search
、
confidential-provider
、
automation
の3リスクを分け、実行前に送信範囲を確認させています。OpenAI APIのデータはデフォルトで学習に使われない一方、保持やZero Data Retentionの適格性はエンドポイントや機能で異なります。「学習されない」だけを見て機密設計を終えるべきではありません。
私自身、クロスボーダー案件で資料共有範囲の確認に何度も時間を使いました。面倒に見える確認こそ、後から説明できるプロダクトにするための機能です。
ここまでを、別の業務アプリにも持ち込める原則へまとめます。
| 原則 | 実装上の問い |
|---|
| Agent as proposer | AIは提案しているか、それとも不可逆操作を直接実行しているか |
| State before chat | 会話履歴より先に、業務状態と遷移が定義されているか |
| Separate run and decision | 技術的成功と業務的承認を別々に追跡できるか |
| Context minimization | エージェントごとに必要最小限の情報だけ渡しているか |
| Approval-gated chaining | 次工程の自動起動に人の承認が入っているか |
全部を人が確認する設計は、規模が大きくなるとボトルネックになります。だから将来の自動承認を否定する必要はありません。ただし、先に判断状態を記録できる構造を作り、低リスク・高信頼の処理だけを段階的に自動化する方が安全です。ValuScopeの
AUTO_APPROVED
が前方互換としてスキーマに残されているのは、その余地を示していますが、現行Web版は自動承認を生成しません。
設計思想が正しくても、実装の継ぎ目で破れます。今回コードを追って、特に注意したい点は四つありました。
- ベストエフォートの連鎖: 承認記録は成功しても次エージェントの起動が失敗する可能性があります。再送キュー、アラート、補償処理が必要です。
- クライアント側の承認処理: 現行のステージ更新と次工程起動はReact hookが担います。将来はサーバー側コマンドへ寄せ、原子的な監査を強める余地があります。
- 認可の粒度:
authenticated read
と組織分離は同義ではありません。アプリ側のMembership確認だけでなく、データモデルの認可境界を継続監査すべきです。 - プロンプトとポリシーの混同: 「機密を検索語へ入れない」とプロンプトに書くことは補助策です。入力フィルタ、経路分離、ログ監査も必要です。
AWS Lambdaの非同期実行は重複配信が起こり得るため、公式資料も冪等性を求めています。ValuScopeには
sourceKey
と
SUPERSEDED
の系譜がありますが、外部副作用まで含めた冪等性は今後も検証対象です。
私には、AIエージェントを組み込む設計は、プロンプト設計より権限設計に近く見えます。誰が、どの情報を読み、どの状態まで提案し、どの操作だけを人が承認するか。そこが決まれば、モデルやUIは交換できます。
ValuScopeの開発履歴は、計算・資料・ディール管理という業務基盤の上にAIを載せ、最後に受信箱と承認フローを足した流れでした。最初から完全自動化を狙わなかったからこそ、6種類のエージェントを一つの業務状態へ接続できたのだと思います。
次編では、この思想をNext.js Route Handler、Amplify Data、Lambda worker、TanStack Queryのポーリングへどう落としたかを、実装単位で分解します。
次号の記事案
- 案1:AIエージェントの評価基盤を作る — 承認率、再実行率、競合率、ステージ滞留時間をイベントとして記録し、プロンプト改善と業務改善を分離して評価します。
- 案2:SQSとDLQでエージェント実行を堅牢化する — fire-and-forgetのFunction URLをキュー駆動へ移し、重複、再試行、失敗イベント回収を実装します。
- 案3:組織境界を強める認可設計 — Amplifyのowner認可とorganization membershipをどう組み合わせ、マルチテナントの読み書きを検証するかを掘り下げます。
本記事は情報提供を目的としており、特定の銘柄・サービス・投資行動を推奨するものではありません。執筆には生成AIを利用し、ソースコードと公式資料をもとに内容を確認しています。詳細は免責事項をご覧ください。
Designing Agentic Apps: Human-Controlled Automation Lessons from ValuScope
Version note: This article reflects the
valuscope-next
specification, source code, and Git history as of July 12, 2026. The reviewed history spans April 18 through July 12, with 94 commits and 266 tracked files. I separate what the implementation demonstrably does from outcomes that still require production measurement.
Working on CVC deals has made me optimistic about AI and cautious about blurred accountability at the same time. The hardest ValuScope design question was not which model to use. It was where the agent must stop and return control to a person.
Here is the design in compact form.
| Theme | ValuScope's choice |
|---|
| Agent role | Research, organize, propose, and generate artifacts; do not make the investment decision |
| Human role | Review output and approve, reject, or rerun it |
| Automation unit | Six bounded agents instead of one universal assistant |
| State model | Track execution state separately from decision state |
| Confidentiality boundary | Separate public web research from internal document and fund-context analysis |
| Chaining | Advance stages and launch the next agent only after approval |
This is not a dramatic autonomous-investing system. In practice, I think that restraint is the foundation of trust.
The obvious first screen for an AI application is chat. I was tempted by that too. Once I decomposed the investment workflow, however, the center of the product was clearly state rather than conversation.
A ValuScope deal moves through
SOURCED → SCREENING → DD → IC → CLOSED / MONITORING / PASSED
. The required work changes along the way: public research, deck analysis, meeting preparation, diligence questions, and an investment-committee draft. The current implementation therefore assigns six bounded responsibilities.
| Agent | Primary input | Primary output | Human review question |
|---|
| Pipeline ToDo | All active deals | Prioritized actions | Who should verify what now? |
| Web Research | Public company data | Sourced research | Are company claims separated from third-party evidence? |
| Deck Analysis | Stored documents | Thesis and missing information | Did the agent invent anything absent from the deck? |
| Meeting Agenda | Documents and history | Issues and questions | Will answers distinguish advance from pass? |
| Question List | Documents and notes | 20–30 diligence questions | How would each answer change the decision? |
| IC Proposal | Documents and references | Committee memo outline | Are risks, falsifiers, and unknowns explicit? |
The key insight is that an agent is defined by its business responsibility, input boundary, artifact, and next decision, not by its model name. Models are replaceable. Blurred responsibilities remain blurred even after a model upgrade.
The Git history reinforces this sequence. The April 19 application centered on portfolio management, valuation, and document analysis. Deal sub-agents appeared on May 31. Fund context and comparable research followed on June 4. The inbox and approval workflow were integrated in July. Business data and calculations came first, agents came next, and the human control plane came last. In hindsight, that ordering mattered.
The strongest design choice was refusing to compress “the job returned successfully” and “a person approved the result” into one status field.
ValuScope has a
DealAgentRun
for processing history and an
ActionItem
for a human decision. The former moves through
GENERATING / SUCCEEDED / FAILED
; the latter uses
RUNNING / AWAITING_REVIEW / APPROVED / REJECTED / FAILED / SUPERSEDED / DISMISSED
.
| State family | Question answered | Representative states |
|---|
| Execution | Did the technical process finish? | GENERATING , SUCCEEDED , FAILED |
| Decision | What did a person do with the artifact? | AWAITING_REVIEW , APPROVED , REJECTED |
| Lineage | How does this request relate to an older one? | SUPERSEDED |
A model can return valid text that is unusable for an investment decision. A reviewer can reject that text even though the job itself completed normally. Combining those facts damages both incident analysis and auditability.
Approval transitions are also encoded as a deterministic function, not buried in prompt prose. The essential shape is below.
type Plan = {
proposedStatus: 'SCREENING' | 'DD' | 'IC' | null;
nextAgentTypes: string[];
};
function nextOnApprove(
agentType: string,
currentStage: string,
hasDocs: boolean
): Plan {
const plan =
agentType === 'WEB_RESEARCH'
? {
proposedStatus: 'SCREENING' as const,
nextAgentTypes: hasDocs ? ['DECK_ANALYSIS'] : ['MEETING_AGENDA'],
}
: agentType === 'DECK_ANALYSIS' || agentType === 'MEETING_AGENDA'
? { proposedStatus: 'DD' as const, nextAgentTypes: ['QUESTION_LIST'] }
: agentType === 'QUESTION_LIST'
? { proposedStatus: 'IC' as const, nextAgentTypes: ['IC_PROPOSAL'] }
: { proposedStatus: null, nextAgentTypes: [] };
return isForwardStage(currentStage, plan.proposedStatus)
? plan
: { ...plan, proposedStatus: null };
}
This function protects two boundaries. An agent result cannot advance a deal by itself, and approval cannot move the workflow backward. Real investment processes do contain exceptions, but treating an exception as an explicit manual decision produces a cleaner history than mixing it into the default path.
The chat feature follows the same philosophy. When a user asks to move a company to DD, the model does not update the database. It returns a structured proposal. The interface displays old and new values, and the user selects which fields to apply.
I initially thought a confirmation modal would be enough for a human-in-the-loop system. It is not. Another team member may modify a record between proposal generation and approval. ValuScope therefore reloads the current database value and skips any field whose value no longer matches the proposal's
currentValue
.
The responsibilities are deliberately layered:
- The model proposes changes only for whitelisted fields.
- JSON Schema constrains the output shape.
- The UI displays current and proposed values.
- A person selects fields to apply.
- The server revalidates authentication, types, enums, and required fields.
- Only conflict-free updates reach the database.
This appears to reduce the agent's freedom. I see the opposite effect: narrow write authority makes users more comfortable giving the assistant broad analytical tasks.
Confidentiality is not only an encryption question. It is also a routing question. ValuScope's
WEB_RESEARCH
uses web search but does not receive stored deal documents or the fund profile. Document-oriented agents can receive documents and fund strategy, but do not use web search.
That separation creates three distinct paths.
| Path | Information used | External tool | Primary risk |
|---|
| Public research | Company name, site, industry, public description | Web search + OpenAI API | Confidential data leaking into a query |
| Internal analysis | Decks, meeting notes, fund strategy | OpenAI API | Sharing authority, retention, personal data |
| Decision and update | Approval, stage, history | AppSync / database | Incorrect writes, conflicts, authorization gaps |
The UI also distinguishes
web-search
,
confidential-provider
, and
automation
risks and asks for confirmation before execution. OpenAI states that API data is not used for training by default, but retention and Zero Data Retention eligibility differ by endpoint and feature. “Not used for training” is not a complete confidentiality design.
Cross-border projects taught me how much time can disappear into document-sharing decisions. That friction is not accidental overhead. Productizing it makes later explanations possible.
The ValuScope choices generalize into five questions that apply to other operational applications.
| Principle | Implementation question |
|---|
| Agent as proposer | Is the model proposing an action or directly performing an irreversible operation? |
| State before chat | Are workflow states and transitions defined before conversational behavior? |
| Separate run and decision | Can technical success and business approval be inspected independently? |
| Context minimization | Does each agent receive only the information required for its role? |
| Approval-gated chaining | Does a person approve before the next automated step begins? |
Reviewing every output will eventually become a bottleneck. That does not make future auto-approval wrong. A safer sequence is to build decision-state tracking first, collect evidence, and automate only low-risk, high-confidence cases. ValuScope retains
AUTO_APPROVED
in the schema for forward compatibility, while the current web application does not generate that state.
Good principles still fail at implementation seams. Four issues stood out during the code review.
- Best-effort chaining: approval can be recorded even if the next-agent dispatch fails. A durable queue, alert, and compensation path would make this stronger.
- Client-side approval orchestration: the current stage update and next-step dispatch live in a React hook. A server-side command could provide tighter transactional auditing.
- Authorization granularity:
authenticated read
does not automatically equal tenant isolation. Membership checks and model authorization need continuous testing together. - Prompt-policy confusion: telling a model not to put secrets in search queries is only one layer. Input filtering, path separation, and log review are also required.
AWS documents that asynchronous Lambda invocations may be delivered more than once and recommends idempotent handling. ValuScope has
sourceKey
and
SUPERSEDED
lineage, but idempotency across every external side effect remains an area to verify.
Agent application architecture increasingly looks like permission architecture to me. Who can read which context, propose which transition, and perform which operation after whose approval? Once those boundaries are explicit, models and interfaces can evolve without redefining accountability.
ValuScope's history moved from calculations, documents, and deal management to agents, then to an inbox and approval flow. Avoiding full autonomy at the start made it possible to connect six agents to one understandable workflow.
Part two decomposes how this philosophy maps onto Next.js Route Handlers, Amplify Data, a Lambda worker, and TanStack Query polling. Part three covers the operating procedure and a measurement framework for actual effects.
Next Issue Ideas
- Idea 1: Build an evaluation layer for operational agents — Capture approval rate, rerun rate, conflict rate, and stage dwell time so prompt quality and process quality can be evaluated separately.
- Idea 2: Harden agent execution with SQS and a DLQ — Replace Function URL fire-and-forget dispatch with a durable queue and implement duplicate handling, retries, and failed-event recovery.
- Idea 3: Strengthen organization-level authorization — Test how Amplify owner authorization and organization membership should combine in a multi-tenant application.
This article is for informational purposes only and does not recommend any security, product, investment, or securities action. Generative AI assisted the writing, and the content was checked against source code and official documentation. See the disclaimer for details.