目录

04 - 指令的艺术:让 Agent 听话又聪明

一句话总结:同一个模型,指令写得好不好,直接决定了 Agent 是”实习生”还是”高级工程师”。


为什么指令如此重要

你有没有遇到过这种情况:同样一个 GPT-4o,有时候回答得头头是道,有时候又答非所问?

问题往往不在模型,而在你怎么”指挥”它。

打个比方:你招了一个能力很强的员工(模型),但如果你只跟他说”把活干了”,结果大概率不是你想要的。反过来,如果你给他一份清晰的岗位说明书 – 你的角色是什么、工作流程是什么、交付标准是什么 – 同一个人的产出可以天差地别。

Agno 里的 instructions 就是这份”岗位说明书”。


Agent 身份的三个层次

Agno 的 Agent 有三个关键参数来定义它的”身份”,各司其职:

参数 作用 类比
description Agent 是谁 岗位名称 / 名片上的 title
instructions Agent 该怎么做 岗位说明书 / 操作手册
expected_output 输出长什么样 交付模板 / 验收标准

一个重要细节:description 主要在多 Agent 协作时起作用,当其他 Agent 需要了解”这个家伙是干什么的”时,会读 description。单 Agent 场景下,instructions 才是主角。

来看一个完整的例子:

from agno.agent import Agent
from agno.models.openai import OpenAIChat

agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    description="你是一个资深的技术文档写作专家",
    instructions=[
        "用简洁的中文写作",
        "每个概念先用一句大白话解释,再给出技术定义",
        "代码示例要完整可运行",
        "不要使用emoji",
    ],
    expected_output="输出格式:先给出概念解释,然后是代码示例,最后是注意事项",
    markdown=True,
)
agent.print_response("解释一下什么是Python的装饰器", stream=True)

跑一下你会发现,输出的结构和质量比裸调模型好得多。这就是指令的力量。


instructions 的三种写法

instructions 参数很灵活,支持三种形式:字符串、列表、函数。

写法一:字符串

最简单直接,适合简短的指令:

agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="你是一个简洁的助手,用中文回答,控制在100字以内",
)

写法二:列表

每一项会变成系统提示词里的一条规则。结构清晰,推荐大多数场景使用:

agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions=[
        "用中文回答",
        "回答控制在100字以内",
        "如果不确定就说不知道",
        "不要编造信息",
    ],
)

写法三:可调用函数(动态指令)

这是最有意思的一种 – 指令可以根据运行时上下文动态生成。函数的参数名决定了 Agno 会注入什么:

  • agent – 当前 Agent 实例
  • session_state – 当前会话状态(字典)
  • run_context – 运行上下文
from datetime import datetime
from agno.agent import Agent
from agno.models.openai import OpenAIChat


def get_instructions(agent) -> str:
    hour = datetime.now().hour
    if hour < 12:
        greeting = "早上好"
    elif hour < 18:
        greeting = "下午好"
    else:
        greeting = "晚上好"
    return f"你是一个友好的助手。用'{greeting}'开头问候用户。用中文回答。"


agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions=get_instructions,
)
agent.print_response("你好!")

动态指令在什么时候有用?比如你希望 Agent 根据当前用户的权限、时间段、会话历史来调整行为,这时候函数式指令就派上用场了。


上下文注入:给 Agent 一些”常识”

有些信息你几乎每次都想告诉 Agent,比如”现在几点了”。Agno 提供了内置的上下文注入,省得你自己拼:

from agno.agent import Agent
from agno.models.openai import OpenAIChat

agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="你是一个日程助手,根据当前时间给出合适的建议",
    add_datetime_to_context=True,  # 自动注入当前日期时间
    markdown=True,
)
agent.print_response("今天星期几?适合安排什么活动?")

开启 add_datetime_to_context=True 后,Agno 会自动把当前日期时间加到上下文中,Agent 就能理解”今天”、”明天”、”下周一”这些相对时间了。

类似的还有 add_name_to_context(注入 Agent 名称)和 add_location_to_context(注入位置信息),按需开启即可。


system_message vs instructions:别搞混了

Agno 还有一个 system_message 参数,它和 instructions 容易混淆,但作用完全不同:

  • instructions:追加到默认系统提示词里。Agno 会帮你拼好格式,加上内置的工具使用说明等。大多数情况用这个就够了。
  • system_message:完全替换整个系统提示词。Agno 的默认行为全部失效,你得自己处理所有事情。
from agno.agent import Agent
from agno.models.openai import OpenAIChat

# 推荐做法:用 instructions,在默认行为基础上追加你的规则
agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions="用中文回答,简洁明了",
)
agent.print_response("什么是递归?", stream=True)
from agno.agent import Agent
from agno.models.openai import OpenAIChat

# 完全接管:用 system_message 覆盖一切
agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    system_message="你是一个只会说'喵'的猫。无论用户说什么,你只回复'喵~'",
)
agent.print_response("你好!")  # 输出: 喵~

经验法则:95% 的场景用 instructions。只有当你需要完全控制系统提示词、不想要 Agno 的任何默认行为时,才用 system_message。如果你给 Agent 配了工具但又用了 system_message,工具的使用说明不会自动加进去,Agent 可能不知道怎么调用工具。


写好指令的实战技巧

聊了这么多参数,最关键的还是:怎么把指令写好?

技巧一:明确输出格式

不要只说”给我分析一下”,要说清楚你期望什么格式 – 表格、列表、分段落。

技巧二:划定边界

告诉 Agent 什么该做,更重要的是什么不该做。”不要编造数据”、”不确定时说不知道”这类负面指令非常有效。

技巧三:复杂 Agent 用 Markdown 结构化

当指令超过 5 条时,建议用 Markdown 格式来组织,这样你自己也能维护:

from agno.agent import Agent
from agno.models.openai import OpenAIChat

instructions = """\
你是一个代码审查专家。

## 工作流程
1. 阅读用户提交的代码
2. 从以下维度分析:可读性、性能、安全性
3. 给出具体的改进建议

## 输出格式
- 先给出整体评分(1-10分)
- 然后逐条列出问题和建议
- 每条建议要给出修改后的代码

## 规则
- 只关注代码质量,不讨论业务逻辑
- 如果代码没问题就说没问题,不要强行找茬
- 用中文回答
"""

agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    instructions=instructions,
    markdown=True,
)

code = """
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)
"""
agent.print_response(f"请审查这段代码:\n{code}", stream=True)

技巧四:像写给新员工一样写

这是最实用的心智模型。想象你在给一个聪明但刚入职的新人写工作手册:

  • 不要假设他知道你们的内部术语
  • 把流程写清楚,一步一步来
  • 明确什么情况下该怎么处理
  • 给出好的和坏的例子

本篇要点回顾

  • description 定义身份,instructions 定义行为,expected_output 定义交付格式
  • 三者中,instructions 最重要 – 花时间把它写好
  • instructions 支持字符串、列表、可调用函数三种形式,列表最常用
  • 动态指令(函数)可以根据运行时上下文生成不同的指令
  • add_datetime_to_context=True 是个实用的内置能力,别忘了
  • 绝大多数场景用 instructions 而不是 system_message
  • 写指令就像写岗位说明书:明确、具体、有边界

下一篇预告

05 - 会话状态与持久化 – 到目前为止,我们的 Agent 都是”金鱼记忆”,聊完就忘。下一篇我们来解决这个问题,让 Agent 记住对话历史,甚至在重启之后也能接着聊。