第 4 章 · 02 结构化输出约定


文档摘要

第 4 章 · 02 结构化输出约定 本节摘要:本节聚焦 里一个容易被忽略却很关键的设计——给 risk/execution/quant 三个 Agent 的 systemprompt 追加一段「当收到消息时,它包含…请提供…」的结构化输出约定。这段追加文字不在 里,而是直接写在 的字符串拼接里。它做了两件事:一是声明输入契约(你会收到哪几段),二是用编号清单约束输出字段(必须给哪些项)。本节逐行拆这三段追加文字,讲清「输入契约 + 编号清单」为何能显著提升 LLM 输出的可用性,以及它与下游解析、与 prompts.py 里的「prompt 模板」是什么关系。读完本节,你掌握多 Agent 系统里「输出可被下游消费」的 prompt 套路。

第 4 章 · 02 结构化输出约定

本节摘要:本节聚焦 workers.py 里一个容易被忽略却很关键的设计——给 risk/execution/quant 三个 Agent 的 system_prompt 追加一段「当收到消息时,它包含…请提供…」的结构化输出约定。这段追加文字不在 prompts.py 里,而是直接写在 workers.py 的字符串拼接里。它做了两件事:一是声明输入契约(你会收到哪几段),二是用编号清单约束输出字段(必须给哪些项)。本节逐行拆这三段追加文字,讲清「输入契约 + 编号清单」为何能显著提升 LLM 输出的可用性,以及它与下游解析、与 prompts.py 里的「prompt 模板」是什么关系。读完本节,你掌握多 Agent 系统里「输出可被下游消费」的 prompt 套路。

内容来源:原项目源码 autohedge/workers.py(第 37-38、49-50、61-62 行的追加段)、autohedge/prompts.py(模板段),精读并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 逐行读懂 risk/execution/quant 三个 Agent 的追加约定。
  2. 说清追加段做的两件事:输入契约输出约束
  3. 解释编号清单为何能约束 LLM 输出。
  4. 区分 system_prompt 里追加的「运行时约定」与 prompts.py 里的「prompt 模板」。
  5. 体会「输出可被下游消费」对多 Agent 链路的意义。

一、追加段在哪里、长什么样

回顾 workers.py 第 35-45 行的 risk_agent(关注 system_prompt 拼接):

risk_agent = Agent( agent_name="Risk-Manager", system_prompt=RISK_PROMPT.strip() + "\n\nWhen you receive a message, it will contain:\nStock, Thesis, Quant Analysis.\n\nProvide risk assessment including:\n1. Recommended position size\n2. Maximum drawdown risk\n3. Market risk exposure\n4. Overall risk score" + _SYSTEM_SUFFIX, ... )

system_prompt 是三段拼接:RISK_PROMPT.strip() + 追加约定 + _SYSTEM_SUFFIX(时间注入,下节讲)。本节聚焦中间那段「追加约定」。三个 Agent 的追加段结构完全一致,只是字段不同。

二、risk_agent 的追加约定逐行拆

把追加段单独拎出来看:

When you receive a message, it will contain: Stock, Thesis, Quant Analysis. Provide risk assessment including: 1. Recommended position size 2. Maximum drawdown risk 3. Market risk exposure 4. Overall risk score

这段话做了两件事:

件事 1:输入契约(前两行)

When you receive a message, it will contain: Stock, Thesis, Quant Analysis.

预先告诉 LLM:你收到的消息会包含「股票、假设、量化分析」三段。这是输入契约——明确数据来源与组成。

为什么这很重要?因为 handoff 时,Director 交给 risk_agent 的消息是一整段文本,没有字段标签。如果没有这句约定,LLM 可能不知道这段文本里哪些是假设、哪些是量化分析,只能瞎猜。有了这句,LLM 会主动在输入里寻找这三段,解读更准确。

件事 2:输出约束(后五段)

Provide risk assessment including: 1. Recommended position size 2. Maximum drawdown risk 3. Market risk exposure 4. Overall risk score

编号清单要求 LLM 必须给出这 4 项。编号清单的约束力来自:

  • 明确性:每项是一个具体字段(仓位/最大回撤/风险敞口/风险评分),LLM 不会漏。
  • 顺序:编号隐含了展示顺序,LLM 倾向于按 1→2→3→4 组织输出。
  • 可解析:下游(执行 Agent 或 Director)能预期输出形态,便于提取。

💡 核心心法:编号清单是 prompt 工程里性价比最高的招式——一行「1. ... 2. ... 3. ...」就能把 LLM 的自由文本约束成半结构化输出。它不如 JSON schema 严格,但比纯散文可控得多,且 LLM 遵守率高。

三、execution_agent 的追加约定

workers.py 第 49-50 行:

When you receive a message, it will contain: Stock, Thesis, Risk Assessment. Generate trade order including: 1. Order type (market/limit) 2. Quantity 3. Entry price 4. Stop loss 5. Take profit 6. Time in force

结构与 risk 完全对称。注意两个细节:

  • 输入契约变了:现在是「Stock, Thesis, Risk Assessment」——因为执行 Agent 在风控 Agent 之后,收的是风控结果。这体现链路顺序:情绪/量化 → 风控 → 执行,每个 Agent 的输入契约反映它的上游。
  • 输出字段更细:6 项订单字段,且 Order type (market/limit) 给了枚举提示——告诉 LLM 订单类型无非 market 或 limit,别瞎编别的。这种「字段 + 枚举提示」是结构化输出的进阶写法。

四、quant_agent 的追加约定

workers.py 第 61-62 行:

When you receive a message, it will contain: Stock and Thesis from your Director. Generate quantitative analysis with: ticker, technical_score (0-1), volume_score (0-1), trend_strength (0-1), volatility, probability_score (0-1), key_levels (support, resistance, pivot).

这段风格略不同——输出没用编号清单,而是逗号分隔的字段列表,且每个字段标了类型/量程:

  • technical_score (0-1):明确 0~1 量程。
  • volatility:无量程(自由浮点)。
  • key_levels (support, resistance, pivot):复合字段,含三个子项。

这种写法更接近「数据 schema」——它几乎在要求 LLM 输出一段类 JSON。配合 prompts.py 里的 QUANT_ANALYSIS_PROMPT 模板(里面有真正的 JSON 结构,第 432 行起),能看出作者想让量化产出可被程序解析的指标结构

⚠️ 现实澄清:尽管追加段要求量化产出 0~1 的 technical_score 等,但量化 Agent 无真实工具(第 3 章第 2 节)——这些「指标」是 LLM 凭直觉编的,数值看似精确实则虚构。结构化输出能让 LLM 输出「长得像数据」的东西,但不能让它「真的是数据」。真假取决于有没有真工具,不取决于 prompt 多漂亮。

五、追加约定 vs prompts.py 的模板

prompts.py 里还有一组「Prompt 模板」(第 139-202 行),如 RISK_ASSESSMENT_PROMPT:

RISK_ASSESSMENT_PROMPT = """ Stock: {stock} Thesis: {thesis} Quant Analysis: {quant_analysis} Provide risk assessment including: 1. Recommended position size 2. Maximum drawdown risk 3. Market risk exposure 4. Overall risk score """

它是 .format(stock=..., thesis=..., quant_analysis=...) 的字符串模板。注意:这套模板在当前 workers.py 里根本没被使用——五个 Agent 用的是 prompts.py 顶部的五个 PROMPT 常量 + workers.py 里追加的约定,不是这套模板。

那这套模板是干什么的?推测是早期/计划中的「手动拼接 prompt」方案——作者原本想自己用 .format() 拼出完整 prompt 再调 LLM,后来改用 swarms 的 handoffs 机制(让 Director 自动分发),模板就废弃了。但代码没删,留作痕迹。

对比两种方案:

方案 实现 输入填充 现状
模板方案(prompts.py 模板段) 自己 .format() 拼字符串 显式传参 未使用(废弃)
handoffs 方案(workers.py 追加段) swarms 自动分发 Director 把消息塞进上下文 在用

💡 核心心法:这段「废弃模板」是很好的学习材料——它展示了不靠框架时怎么做多步 prompt 拼接。理解它,你就能在不用 swarms 的场景(比如纯 OpenAI SDK)自己实现类似的链路。这也是读开源项目的一大收获:看「没被用的代码」能反推出设计的演变。

六、为何要结构化:多 Agent 链路的可消费性

结构化输出的根本动机:让下游能消费上游的产出。在 AutoHedge 的链路里:

Director → (假设) → quant → (指标) → risk → (风控) → execution → (订单)

每个箭头都是「上游 LLM 产出文本 → 下游 LLM 读」。如果上游输出是自由散文,下游 LLM 解读时容易遗漏或误读。结构化约定(输入契约 + 编号清单)相当于上下游之间的协议——上游按协议产出,下游按协议解读,链路稳定性大增。

不过,AutoHedge 的结构化只到「半结构化文本」(编号清单),没到「严格 JSON」。后者更可控(LLM 输出可直接 json.loads),但对 LLM 的指令遵循要求更高。生产系统往往用 OpenAI 的 JSON modefunction calling 强制结构化,而非仅靠 prompt。

七、本节要点回顾

  1. 追加段位置:不在 prompts.py,而在 workers.py 的字符串拼接里(risk/execution/quant 三个 Agent 各一段)。
  2. 两件事:输入契约(你会收到 Stock/Thesis/...) + 输出约束(编号清单要哪些字段)。
  3. 编号清单:性价比最高的 prompt 招式,把自由文本约束成半结构化;LLM 遵守率高,下游可预期。
  4. 链路顺序在契约里:execution 的契约含 Risk Assessment(其上游是 risk);quant 的契约是 Stock + Thesis(其上游是 director)。
  5. quant 最接近 schema:用字段 + 类型/量程((0-1))描述输出,近乎要求类 JSON;但仍受限于无真实工具。
  6. 模板段废弃:prompts.py 的 RISK_ASSESSMENT_PROMPT.format() 模板未被使用,是早期手动拼接方案的残留,反映设计从「手拼」到「handoffs」的演变。
  7. 半结构化 vs 严格 JSON:AutoHedge 只到半结构化文本;生产常用 JSON mode/function calling 强制结构化。

下一节,我们看 workers.py 顶部那段 _SYSTEM_SUFFIX——它是 AutoHedge 让 LLM「知道现在是几点」的巧妙设计。


发布者: 作者: 灏天文库 转发
评论区 (0)
U