一只用 AI Agent 搭副业产线的程序员上篇我们写了一个 50 行的 Go 程序跟 DeepSeek 对话。你肯定注意到了代码里三个参数MaxTokens、Temperature还有Messages那个会越来越长的数组。这三个东西说简单也简单——网上一搜一大堆解释。但我发现大部分文章讲完定义就停了你没有「手感」。这篇文章不一样。我们做实验。实验环境10 行代码搭一个测试台先把测试台搭好后面所有实验都在这个基础上跑packagemainimport(bytesencoding/jsonfmtnet/httposstrings)typeMessagestruct{Rolestringjson:roleContentstringjson:content}typeRequeststruct{Modelstringjson:modelMaxTokensintjson:max_tokensTemperaturefloat64json:temperatureMessages[]Messagejson:messages}funccallLLM(messages[]Message,tempfloat64,maxTokensint)string{apiKey:os.Getenv(DEEPSEEK_API_KEY)req:Request{Model:deepseek-v4-pro,MaxTokens:maxTokens,Temperature:temp,Messages:messages,}body,_:json.Marshal(req)httpReq,_:http.NewRequest(POST,https://api.deepseek.com/anthropic/v1/messages,bytes.NewReader(body))httpReq.Header.Set(x-api-key,apiKey)httpReq.Header.Set(anthropic-version,2023-06-01)httpReq.Header.Set(Content-Type,application/json)resp,_:http.DefaultClient.Do(httpReq)deferresp.Body.Close()varresultmap[string]interface{}json.NewDecoder(resp.Body).Decode(result)// 简化处理生产环境请用 SSE 流式ifcontent,ok:result[content].([]interface{});oklen(content)0{iftext,ok:content[0].(map[string]interface{})[text].(string);ok{returntext}}return}行了一套通用工具函数。接下来的实验代码都基于这个。实验一Token——你以为在写字其实在烧钱我问你一个问题「今天天气真好」是几个字6 个字。但对 AI 来说不是。DeepSeek 看到的实际是今天 - [token_8843] 天气 - [token_16782] 真 - [token_99] 好 - [token_1962]中文一个字 1-2 个 token一个英文单词 1-2 个 token。你写 Prompt 觉得只打了 100 个字实际上可能已经烧了 150 个 token。为什么你要关心这个因为按 token 计价。模型输入价格每 1M token输出价格每 1M tokenDeepSeek V4 Pro¥1¥4DeepSeek V4 Flash¥0.3¥1.2GPT-4o¥35¥140Claude Opus 4¥105¥420一个稍微认真的 Prompt 加上上下文文档轻松上万 token。如果用的是 GPT-4o一两次调用就是几毛钱。一个 Agent 循环 10 轮几块钱就没了。动手试一下funcmain(){shortPrompt:你好请用一句话解释什么是递归。longPrompt:shortPromptstrings.Repeat(请务必详细解释,100)// 一不留神就加了 1000 个中文字 ≈ 1500 token}这个意识不是你今天学了明天就精通的。但下次你写 Prompt 的时候脑子里会有一个声音「这行字不是免费的。」后面讲 RAG 和 Agent 的时候你会深刻理解为什么这是 Agent 开发最核心的资源管理问题。实验二温度——同一个问题三个答案温度是最容易被误解的参数。很多人以为温度越高越「聪明」但实际上温度跟智商没关系——它只控制一样东西模型敢不敢选「不太确定」的下一个词。我们跑一个实验。同一个问题用三个温度各跑 3 次funcmain(){prompt:[]Message{{Role:user,Content:用一句话解释什么是 goroutine不要比喻。},}for_,temp:range[]float64{0.0,0.7,1.5}{fmt.Printf(\n Temperature %.1f \n,temp)fori:0;i3;i{result:callLLM(prompt,temp,100)fmt.Printf(第%d次: %s\n,i1,result)}}}实际跑出来的结果有删减 Temperature 0.0 第1次: Goroutine 是 Go 语言中的轻量级线程由 Go 运行时调度管理。 第2次: Goroutine 是 Go 语言中的轻量级线程由 Go 运行时调度管理。 第3次: Goroutine 是 Go 语言中的轻量级线程由 Go 运行时调度管理。 → 三次完全一样像教科书。 Temperature 0.7 第1次: Goroutine 是 Go 语言中由运行时管理的轻量级并发单元。 第2次: Goroutine 是 Go 的轻量级线程通过 go 关键字启动由运行时调度。 第3次: Goroutine 是 Go 运行时管理的轻量级线程比操作系统线程更轻。 → 意思一样措辞不同每次略有变化。 Temperature 1.5 第1次: Goroutine 是 Go 语言的并发原语它是一个由运行时管理的轻量级执行单元。 第2次: Goroutine 可以理解为 Go 语言内置的轻量级线程由协程调度器管理。 第3次: 在 Go 语言中goroutine 是实现并发的核心机制它是一个轻量级的执行线程。 → 开始换着花样说偶尔用词不够精确。一个我踩坑的经验我做那个日报 Agent 的时候一开始默认温度 0.7。结果生成的周报偶尔会用「该同志表现优异」这种莫名其妙的措辞。降到 0.1 之后输出稳定了每天都一样的格式。温度选错了不是「质量差一点」是能不能用的区别。实验三上下文窗口——AI 的「金鱼记忆」金鱼的记忆据说只有 7 秒。AI 模型的记忆取决于你花了多少钱买的上下文窗口。做一个最直观的实验——故意让 AI 忘了你叫什么funcmain(){messages:[]Message{{Role:user,Content:我叫张小华是一名 Go 后端开发。},{Role:assistant,Content:好的张小华记住了。},}// 插入 50 轮无关对话模拟「聊了很久」fori:0;i50;i{messagesappend(messages,Message{Role:user,Content:fmt.Sprintf(第%d个问题Go 的 defer 执行顺序是什么,i)},Message{Role:assistant,Content:fmt.Sprintf(第%d个回答defer 按后进先出LIFO顺序执行。,i)},)}// 最后问一个最初才知道答案的问题messagesappend(messages,Message{Role:user,Content:我还记得我刚才说我叫什么吗},)result:callLLM(messages,0.1,100)fmt.Println(result)}如果你把 50 改成 500——当最早的对话被挤出上下文窗口时——AI 会说「抱歉你没有告诉过我你的名字。」它不是忘了。是「看不见」了。一个残酷的事实你调用 API 的时候API 不会帮你「记住」任何东西。每一轮对话你都必须把整段历史重新传过去。第 1 轮传 10 条消息第 100 轮传 100 条。每轮都在重复烧 token越烧越多。这就是为什么后面我们要讲「上下文窗口预算策略」——不管理好窗口你的 Agent 跑着跑着就破产了。三个概念的关系一张表总结概念是什么你会遇到的问题Token计费单位也是信息密度单位Prompt 写太长烧钱写太短信息不够温度控制输出的随机性高了不可靠低了没创意上下文窗口模型的「工作记忆」上限聊多了忘记塞多了贵三个概念互相制约温度低 窗口大 可以做精准的长文档分析如代码审查温度高 窗口小 适合简短创意任务如起名温度低 窗口小 适合确定性短任务如提取数据没有「最好」的设置只有「适合当前任务」的设置。作业把上面的测试台代码跑一遍改三个参数观察输出。你会发现一个微妙的事你不会再觉得 AI 很神秘了。你知道它怎么工作、为什么这么回答、什么情况下可能出错。下一篇我们做一件狠事——同一个任务扔给 DeepSeek、通义千问、GPT-4o、Claude 四个模型跑。看谁的代码最靠谱、谁最便宜、谁最会编。数据说话。关注我别错过。 一只用 AI Agent 搭副业产线的程序员全平台同名虾哥不加班需要定制 AI 工具来聊聊 → lob_ai源码GitHub - lobster-bujiaban