第十三天后端代码学习笔记 大模型第十三天后端代码学习笔记第十三天讲的是提示词工程算岗位匹配度、还有 function calling就是让大模型能调外部工具。项目里相关文件主要是这几个app/services/job_service.py算岗位匹配度的地方llm/case5.pyfunction calling 入门用天气查询当例子llm/case6.pyfunction calling 接真实的学历验证接口还带了 Redis 缓存1 用提示词工程算岗位匹配度这个其实没用到 function calling就是纯提示词prompt工程。在job_service.py里有个resume_submission_detail方法它的活儿是HR 在后台看某个人投某个岗位的详情时顺便让大模型分析一下这个人跟这个岗位有多匹配。它做的事情分两步第一步把岗位信息和简历信息从数据库里捞出来。岗位这边有职位名称、工作地点、薪资、经验要求、学历要求、性别要求、职位描述、任职要求简历那边更杂有基本信息、期望职位、期望薪资、工作经历、项目经历、教育经历、专业技能、语言能力、证书荣誉……反正能塞的都塞进去了。第二步把这些拼成一个超级长的 prompt 丢给大模型。prompt 大概长这样我截重点##角色设定: 你是一个经验丰富的人力资源专家 ##任务描述 根据求职者简历内容和岗位的职位描述,分析岗位匹配度和理由 ##输入数据 1.岗位的职位描述 1.1:职位名称:{job.job_name} 1.2:工作地点: {job.work_location} ...一堆岗位字段 2.求职者简历内容: 2.1:求职者性别(1-男2-女):{resume_basic_info.gender} ...一堆简历字段 ##输出数据: 以JSON格式输出,包含以下字段: job_matching_degree:岗位匹配度(0-100)百分比 matching_reason: 重要禁止输出任何思考、推理、标签直接输出JSON结果不要输出其他文字。 ## 输出示例: {job_matching_degree: 80%, matching_reason: ...}调模型那段就很朴素clientOpenAI(api_keyos.environ[DASHSCOPE_API_KEY],base_urlhttps://ws-89t66lrlxx0rdobw.cn-beijing.maas.aliyuncs.com/compatible-mode/v1)completionsclient.chat.completions.create(modelqwen-plus,messages[{role:user,content:prompt}])rescompletions.choices[0].message.contentreturnres说白了就是把所有信息塞进一个 user 消息让大模型当 HR 专家按指定 JSON 格式吐出匹配度和理由。我觉得这块最值得学的点是那个输出格式约束——你不光告诉它要输出 JSON还给了输出示例并且明确说禁止输出思考过程直接给 JSON。不然大模型很喜欢先啰嗦一大段好的我来帮你分析前端解析就麻烦了。2 function calling 是干嘛的先说为啥需要它。前面算匹配度那种大模型自己就能干因为答案在它脑子里它是被训练过的。但有些事它干不了比如北京今天天气咋样——它训练数据里没有实时天气它就瞎编。function calling 就是给大模型装外挂你提前告诉它你有一堆工具可以用每个工具是干嘛的、要什么参数。大模型看到用户问题后如果觉得需要查天气它就告诉你我要调get_current_weather这个工具参数是北京然后你的程序真的去查天气把结果再喂回给大模型大模型最后组织成自然语言回答用户。一句话大模型负责想调哪个工具、给什么参数程序负责真去执行工具各干各的。3 function calling 的工作流程整个流程五步我画个大概你定义好tools工具清单跟着消息一起发给大模型大模型回你我要调xxx工具参数是yyy返回里带着tool_calls你的程序根据tool_calls真的去执行那个工具函数拿到结果你把工具结果拼成一条role: tool的消息再丢回给大模型大模型拿到工具结果组织成最终回答返回关键就是第 4 步那条role: tool的消息它必须带上tool_call_id大模型才知道这个结果是回给哪次工具调用的。4 function calling 入门案例天气查询看llm/case5.py。先定义工具清单tools[{type:function,function:{name:get_current_weather,description:当你想查询指定城市的天气时非常有用。,parameters:{type:object,properties:{location:{type:string,description:城市或县区比如北京市、杭州市、余杭区等。,}},required:[location],},},},]然后弄个假的天气查询函数真实项目里这里才是真去调天气 APIdefget_current_weather(arguments):weather_conditions[晴天,多云,雨天]random_weatherrandom.choice(weather_conditions)locationarguments[location]returnf{location}今天是{random_weather}。发请求的时候把tools带上defget_response(messages):completionclient.chat.completions.create(modelqwen-plus,extra_body{enable_thinking:False},messagesmessages,toolstools,)returncompletion然后就是判断大模型有没有要调工具ifcompletion.choices[0].message.tool_callsisNone:print(不需要调用工具)print(completion.choices[0].message.content)else:print(需要调用工具)tool_callscompletion.choices[0].message.tool_callsfortool_callintool_calls:tool_idtool_call.idfunc_nametool_call.function.name func_argumentstool_call.function.arguments function_mapping{get_current_weather:get_current_weather}tool_resultfunction_mapping[func_name](json.loads(func_arguments))tool_message{content:tool_result,role:tool,tool_call_id:tool_id}messages.append(tool_message)completionget_response(messages)print(f最终的结果是:{completion.choices[0].message.content})这里function_mapping是个字典把工具名映射到真正的 Python 函数。大模型只告诉你要调哪个、给啥参数具体执行是你这边function_mapping[func_name](...)干的。这个 case5 有两个小坑case6 里修好了第 56 行messages.append(user_messages)而user_messages本身是个列表append 进去会变成列表套列表应该用messages.extend(user_messages)第 59 行messages.append(completion.choices[0].message)直接把消息对象塞进去规范点应该用completion.choices[0].message.model_dump()转成字典5 function calling 接学历验证接口llm/case6.py是真实业务了——接梦远学历验证接口www.apimy.cn。这次定义了两个工具天气和学历验证defacademic_credential_verification(arguments):vcodearguments[vcode]keyfboss:llm:academic_credential_verification:{vcode}redis_verification_datar.get(key)ifredis_verification_dataisNone:BASE_URLfhttps://www.apimy.cn/api/xxw/bgcx?key{os.getenv(API_KEY)}responserequests.post(BASE_URL,data{vcode:arguments[vcode]},timeout30)response.raise_for_status()dataresponse.json()r.set(key,json.dumps(data,ensure_asciiFalse))returnjson.dumps(data,ensure_asciiFalse)else:returnredis_verification_data这块比 case5 多了两样好东西一是真的发 HTTP 请求。用requests.post去调第三方学历验证接口拿到 JSON 结果。二是加了 Redis 缓存。用验证码vcode当 key先r.get查缓存没有才去调接口调完r.set存起来。同一个验证码第二次查就直接走缓存不用再打第三方接口——省次数也快。还有 case6 把 case5 那两个坑都修好了messages.extend(user_messages)用 extend 不是 append、messages.append(completion.choices[0].message.model_dump())用 model_dump 转字典。调用流程跟 case5 一样也是tool_calls→ 执行函数 → 塞role:tool消息 → 再请求一次拿最终答案。这些怎么接到 FastAPI 接口里课程里 case5/case6 还是脚本真要变成后端接口套路跟前面多轮对话那章差不多把 tools 和函数定义放到接口文件里写一个路由比如router.post(/verify_academic)接收user_id、vcode这种参数把函数调用那段包成生成器配合StreamingResponse就能流式输出前面第十二章做过会话上下文用 Redis 存key 设计成boss:llm:academic:{user_id}:{session_id}这种要注意的是function calling 这套多轮比普通对话多一步每轮都得把role:tool的消息正确塞回 messages否则大模型不知道工具结果对应哪次调用容易乱。提示词工程算匹配度把岗位简历拼成大 prompt约束输出 JSON让大模型当 HR 打分。简单但实用。function calling大模型管调哪个工具、给啥参数程序管真执行结果用role:tool消息回传。case5 是玩具例子天气case6 是真实例子学历验证还带了 Redis 缓存。代码都不难难的是理解那条 messages 链路怎么一步一步拼对的。我也是对着打印出来的completion.model_dump_json()一点点看才搞明白的。