三、《从零手撸 Agent》 · system prompt 与核心参数:调好你的旋钮

上一篇讲了 messages 的骨架。这一篇深入两个可调控的东西:system prompt 怎么写才有效,以及 API 的几个关键参数到底在控制什么。参数部分全部配实验,建议边跑边读。

一、system prompt:写给模型的" 岗位说明书"

1.1 一个对比例子

不用 system prompt:

ini 复制代码
messages = [{"role": "user", "content": "帮我看看这段代码有什么问题:x = 5 / 0"}]

回答可能很啰嗦:先讲什么是除法,再讲异常处理体系,最后才说 "你除以零了"

用 system prompt:

ini 复制代码
messages = [
    {"role": "system", "content": "你是一个代码审查员。只指出问题和修法,每条不超过两行,不讲背景知识。"},
    {"role": "user", "content": "帮我看看这段代码有什么问题:x = 5 / 0"},
]

回答:除以零错误。改为先判断除数是否为 0,或用 try/except 捕获 ZeroDivisionError。

同样的问题,输出天差地别。system prompt 决定模型" 用什么身份、什么方式" 回答。

1.2 一个实用的 system prompt 模板

有效的 system prompt 通常包含这四块(按需取舍):

ini 复制代码
SYSTEM_PROMPT = """
# 角色
你是一个Python代码审查助手。

# 行为规则
1. 只指出问题,不重写整个文件
2. 每个问题格式:[严重程度] 位置 - 问题 - 建议修法
3. 不确定的地方明确说"不确定",禁止猜测

# 输出格式
用Markdown列表输出,最多5条,按严重程度排序。

# 边界
如果代码与Python无关,回复"仅支持Python代码"。
"""

四块分别是:角色(你是谁)→ 规则(怎么做)→ 格式(输出长什么样)→ 边界(什么时候拒绝)。

1.3 写 system prompt 的三个新手误区

  • 误区一:堆形容词。"你是一个非常非常专业的专家"------ 没用。模型不因为夸它而变强。要写可执行的规则,不写情绪。
  • 误区二:规则互相矛盾。"回答要详尽" + "不超过 50 字"------ 模型只能随机服从一个。写完通读一遍,删掉冲突项。
  • 误区三:用否定句写期望行为。"不要啰嗦" 不如" 每条不超过两行"。模型对正向指令的服从度更高;否定句只在划红线时用("禁止编造 API 名称")。

二、参数详解:每个都做实验

2.1 temperature:随机性旋钮

原理一句话:模型每生成一个 token,其实是对所有候选词算出一个概率分布;temperature 决定从这个分布里抽样时的" 冒险程度"。

  • 0:永远选概率最高的词 → 同样输入几乎得到同样输出(确定性)
  • 越高(如 1.5):低概率词也有机会被选中 → 输出多变、有创意、也更不稳定

实验代码(同一个刁钻问题,不同 temperature 各跑 3 次):

ini 复制代码
def ask(temp: float) -> str:
    resp = client.chat.completions.create(
        model="deepseek-chat",
        temperature=temp,
        messages=[{"role": "user", "content": "用一个比喻解释什么是递归,一个词的比喻也算"}],
    )
    return resp.choices[0].message.content[:30]

for t in (0, 0.7, 1.5):
    print(f"--- temperature={t} ---")
    for _ in range(3):
        print(" ", ask(t))

你会观察到:t=0 时三次输出几乎相同;t=1.5 时三次各不相同,而且偶尔出现奇怪的比喻。

怎么选:

场景 推荐 原因
代码生成、数据抽取、分类 0 ~ 0.3 要稳定可复现
日常对话、总结改写 0.5 ~ 0.8 平衡
创意写作、起名字 0.9 ~ 1.2 要发散

本系列属于 Agent 开发,几乎全程 0~0.3------ 你要的是一个可靠的执行者,不是艺术家。

2.2 max_tokens:输出长度上限

ini 复制代码
resp = client.chat.completions.create(
    model="deepseek-chat",
    messages=[...],
    max_tokens=100,   # 回答最多100个token,超过就硬截断
)

两个用途:

  1. 省钱护栏:防止模型失控输出长文
  2. 强制造短回答:配合" 用一句话回答" 的提示效果更好

注意一个坑:如果输出被截断,resp.choices 0.finish_reason 会是 "length" 而不是 "stop"。调试时发现回答莫名断在半句话,先检查这个字段:

go 复制代码
print(resp.choices[0].finish_reason)  # "stop"=正常结束  "length"=被截断

2.3 model:选哪个模型

同一家通常有多个模型档位(如 deepseek-chat /deepseek-reasoner),规律:

  • 普通对话模型:快、便宜,适合 Agent 里的常规节点
  • 推理模型(reasoner 类):贵、慢,但复杂问题正确率高,第 09 篇详解

工程经验:不要全程用最贵的。路由 / 格式化 / 简单判断用便宜模型,关键决策才上推理模型 ------ 这是成本工程的基本功。

2.4 stream:流式开关

stream=True # 逐 token 返回(第 04 篇整篇讲它) 这里先记住参数名即可。

三、把参数和 system prompt 组合成一个可复用的函数

从这篇开始,我们会反复用到一个封装好的 chat () 函数,建议存成 llm_utils.py(_utils.py),后续文章直接 import:

python 复制代码
# llm_utils.py
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
    base_url="https://api.deepseek.com",
)

def chat(
    messages: list[dict],
    model: str = "deepseek-chat",
    temperature: float = 0.3,
    max_tokens: int = 1024,
) -> str:
    """统一封装的LLM调用。Agent开发默认低temperature。"""
    resp = client.chat.completions.create(
        model=model,
        messages=messages,
        temperature=temperature,
        max_tokens=max_tokens,
    )
    if resp.choices[0].finish_reason == "length":
        print("[警告] 输出被max_tokens截断")
    return resp.choices[0].message.content

# 用法示例:
if __name__ == "__main__":
    print(chat([
        {"role": "system", "content": "你是简洁的编程助手。"},
        {"role": "user", "content": "一句话解释什么是异步编程。"},
    ]))

封装的好处:参数默认值统一(所有调用都是 0.3),截断警告自动打,换模型只改一处。

四、一个综合实验:观察" 规矩" 的服从度

测试 system prompt 在长对话中会不会失效:

css 复制代码
system = "你回答任何问题都只能用'是'或'否'。"
history = [{"role": "system", "content": system}]

for q in ["Python是编程语言吗?", "天空是蓝的吗?", "详细介绍一下Python的历史",          "详细讲讲图灵的故事"]:
    history.append({"role": "user", "content": q})
    a = chat(history, temperature=0)
    history.append({"role": "assistant", "content": a})
    print(f"Q: {q}\nA: {a[:50]}\n")

典型现象:前几轮严格答" 是 / 否",到后面开始" 越狱" 变长篇大论。结论:system prompt 不是硬约束,是软引导,上下文越长服从度越低。两个对策:

  1. 重要格式要求在最后一轮 user 消息里再强调一次(末尾指令服从度最高)
  2. 输出必须严格结构化时,用代码解析 + 失败重试兜底,而不是相信 prompt(第 15 篇讲 OutputParser 的动机就在这)

五、小结

  1. system prompt 四块结构:角色 → 规则 → 格式 → 边界;写正向可执行的规则
  2. temperature 0~0.3 用于 Agent;实验证明 0 确定性强
  3. max_tokens 是护栏,检查 finish_reason 判断截断
  4. 模型分档混用:便宜模型干杂活,推理模型干难活
  5. system prompt 会随对话变长而失效 ------ 重要约束要末尾重申 + 代码兜底

六、自测

  • ☐ 用四块结构给" 外卖推荐助手" 写一个 system prompt
  • ☐ 跑 temperature 实验,亲眼看到 0 和 1.5 的差别
  • ☐ 把 max_tokens 设成 20 问一个长问题,观察 finish_reason

下一篇:04 流式输出 ------ AI 是一个字一个字想出来的,这个特性怎么用代码接住。

写在最后

如果想系统、完整地吃透 Harness、Hermes 整套前沿智能体开发体系,完成从只会调模型到可控、高质量、可落地的 AI 工程交付进阶,可以关注慕课网近期上新的《Harness&Hermes 多智能体开发特训营》

相关推荐
卷无止境1 小时前
除了写代码,AI智能体还能帮开发者做什么
人工智能·python
我不会起名字3221 小时前
一天一道算法题(26):栈的简单应用
java·数据结构·python·算法·leetcode·golang·
夏文强1 小时前
DeepSeek Harness 可追溯性实战:会话日志的 resume、fork 与 replay
人工智能·开源·大模型·agent·deepseek
爱吃苹果的梨叔1 小时前
AI 算力监控中心怎么建?分布式坐席 + 大屏联动 + 过程回放
人工智能·分布式·python
JarmanYuo1 小时前
YOLO 涨点研究(六):网络结构改进之小目标增强篇1——无人机视角下的车辆与行人检测
人工智能·pytorch·python·yolo·计算机视觉·无人机
烬羽1 小时前
给 Agent 一个检索式记忆:把对话历史存进 Milvus,该记的都记得
javascript·数据库·agent
bcbnb1 小时前
Flutter-Notebook代码混淆:Android与iOS平台安全配置
后端·ios
2601_962297251 小时前
python自带缓存lru_cache用法及扩展的使用_python
python·缓存·装饰器·lru_cache·my_cache