第 4 章 · 03 时间注入与上下文管理 本节摘要:本节讲清两个容易被忽略的工程细节——时间注入与上下文管理。先看 顶部那段 :它在模块加载时用 生成一行「Current date and time ...」并拼到每个 Agent 的 systemprompt 末尾,让 LLM 知道「现在」。这看似不起眼,却对交易场景至关重要——LLM 的训练数据有截止日期,不告诉它「今天」,它会把「最新」当成训练时的新鲜事。再看上下文管理:五个 Agent 都设 (单轮推理)、三个专家设 (限上下文)。本节讲清这两项如何共同决定一次 Agent 调用的成本与稳定性。读完本节,你理解 LLM 「没有时间感」这一固有缺陷,以及 AutoHedge 用一行字符串修补它的巧思与局限。
本节摘要:本节讲清两个容易被忽略的工程细节——时间注入与上下文管理。先看
workers.py顶部那段_SYSTEM_SUFFIX:它在模块加载时用datetime.now()生成一行「Current date and time ...」并拼到每个 Agent 的 system_prompt 末尾,让 LLM 知道「现在」。这看似不起眼,却对交易场景至关重要——LLM 的训练数据有截止日期,不告诉它「今天」,它会把「最新」当成训练时的新鲜事。再看上下文管理:五个 Agent 都设max_loops=1(单轮推理)、三个专家设context_length=16000(限上下文)。本节讲清这两项如何共同决定一次 Agent 调用的成本与稳定性。读完本节,你理解 LLM 「没有时间感」这一固有缺陷,以及 AutoHedge 用一行字符串修补它的巧思与局限。
内容来源:原项目源码
autohedge/workers.py(第 19-24 行_SYSTEM_SUFFIX、各 Agent 的max_loops/context_length),精读并套用体系化模板。
阅读完本节,你应当能够:
_SYSTEM_SUFFIX 的构造代码。max_loops=1 与 context_length=16000 的成本含义。workers.py 第 19-24 行,模块级代码:
_NOW = datetime.now() # Exact date and time for all agent system prompts (simple, single line) _DATE_TIME_LINE = _NOW.strftime("%A, %B %d, %Y at %H:%M") if _NOW.tzinfo: _DATE_TIME_LINE += f" {_NOW.tzname() or ''}" _SYSTEM_SUFFIX = f"\n\nCurrent date and time (use this as now): {_DATE_TIME_LINE.strip()}"
逐行解读:
_NOW = datetime.now():取模块加载时刻的本地时间(无时区)。_NOW.strftime("%A, %B %d, %Y at %H:%M"):格式化成类似 Tuesday, August 05, 2026 at 14:30 的字符串。%A 星期、%B 月份、%d 日、%Y 年、%H:%M 时分。if _NOW.tzinfo::如果时间带时区,追加时区缩写(如 UTC、CST)。但 datetime.now() 默认不带时区,所以这分支通常走不到——除非系统或上层设了 tzinfo。_SYSTEM_SUFFIX = ...:把格式化后的时间行包进一句指令:「Current date and time (use this as now): ...(当前日期时间,把它当作 now)」。注意前导 \n\n——保证它与原 prompt 之间有空行分隔。最终 _SYSTEM_SUFFIX 形如:
Current date and time (use this as now): Tuesday, August 05, 2026 at 14:30
看 workers.py 里五个 Agent 的 system_prompt,每一个都拼了 _SYSTEM_SUFFIX:
sentiment_agent = Agent(..., system_prompt=SENTIMENT_PROMPT + _SYSTEM_SUFFIX, ...) risk_agent = Agent(..., system_prompt=RISK_PROMPT.strip() + "..." + _SYSTEM_SUFFIX, ...) execution_agent = Agent(..., system_prompt=EXECUTION_PROMPT.strip() + "..." + _SYSTEM_SUFFIX, ...) quant_agent = Agent(..., system_prompt=QUANT_PROMPT.strip() + "..." + _SYSTEM_SUFFIX, ...) director_agent = Agent(..., system_prompt=DIRECTOR_PROMPT + _SYSTEM_SUFFIX, ...)
无论角色如何,每个 Agent 都被告知「现在」。这反映作者的判断:时间感对所有 Agent 都重要——情绪要判断「这条新闻是不是过时」、量化要判断「这个指标是不是最新」、风控要判断「这个事件是否已发生」、执行要判断「这个报价是否还有效」。
这是 LLM 应用的一个固有缺陷:
在交易场景,这个缺陷是致命的。举例:
AutoHedge 的解法很轻量——一行字符串注入:Current date and time (use this as now): ...。LLM 读到这句,会把这行时间作为「现在」的参考,后续推理就能锚定时间。
💡 核心心法:LLM 是「凝固在训练时刻的大脑」——它的知识停在某个日期,推理能力是通用的,但「事实」是过期的。给 system_prompt 注入当前时间,相当于给这个大脑「装一个时钟」,让它能把通用推理锚定到当下。这是几乎所有 LLM 应用都该做的基本功(也是 ChatGPT 系统消息里都有时间行的原因)。
AutoHedge 这套注入有个重要局限:时间是模块加载时刻,不是 Agent 调用时刻。
看代码:_NOW = datetime.now() 是模块级语句,在 import autohedge.workers 时执行一次,之后 _SYSTEM_SUFFIX 就固定了。如果你启动一个长驻进程(比如 REPL),早上 9 点 import,到下午 3 点调 Agent,注入的时间还是早上 9 点——差了 6 小时。
这个局限的影响:
要修正也不难——把时间注入从模块级移到 Agent.run 调用前(每次调用重新生成)。但 AutoHedge 没这么做,这是它的一个工程粗糙点。
⚠️ 现实澄清:对教学项目,这个局限无伤大雅(你不会让 REPL 开几天)。但如果你想把这套架构用于生产,时间注入必须改成每次调用时刷新,否则长驻服务的时间感会失真,交易决策的时效判断会出错。
五个 Agent 都设 max_loops=1(第 3 章已提)。从上下文管理角度,它的含义:
max_loops=1 意味着 Agent 收到任务后,只做一轮推理就产出结果,不自我反思迭代。成本含义:
代价是质量:复杂问题一次想不清楚,可能需要多轮「反思→修正」。AutoHedge 选单轮是教学项目的合理简化。
风控/执行/量化三个专家设了 context_length=16000(token 数)。含义:
为什么设小?
注意情绪 Agent 没设 context_length(用 swarms 默认),Director 也没设。这又是一处定义不一致——大概是因为 Director 的输入是用户任务(短),情绪的输入是新闻摘要(也不太长),作者觉得不用显式设。但不一致本身是代码异味。
注意 _SYSTEM_SUFFIX 总是拼在 system_prompt 的最末尾(在追加约定之后)。这不是随意选择:
这是 prompt 工程的小技巧:重要信息放头尾,次要信息放中间。时间属于「重要且简短」的信息,放末尾合适。
system_prompt = 基础角色(prompts.py) + 运行时约定(workers.py 追加) + 时间注入(_SYSTEM_SUFFIX) ↑ max_loops=1, context_length=16000 共同约束一次调用
至此第 4 章讲完了 prompt 工程的三块:「写什么内容」(§01)、「怎么约束输出」(§02)、「怎么管理上下文」(§03)。下一章我们看用户怎么和这套系统交互。
_SYSTEM_SUFFIX 构造:datetime.now() → strftime 格式化 → 包进「Current date and time (use this as now): ...」;五个 Agent 全部注入。max_loops=1:单轮推理,省钱省时、上下文不膨胀;代价是质量(复杂问题难一次想清)。context_length=16000:主动封顶上下文(~12K 词),限成本、防分心、够用;情绪与 Director 漏设是不一致。下一章,我们离开 Agent 内部,看用户怎么和 AutoHedge 交互——从
cli.py的 Rich 美化 REPL 开始。