AIGC-李宏毅-從語言模型到 AI Agent

李宏毅《生成式人工智慧與機器學習導論2025》课程学习笔记。

资源

正文

课程

webp

如果 LLM 的输出 f(x)f(x) 不达预期,而模型参数 ff 无法被改变,唯一可以做的就是提供合适的输入 xx

webp

提供更好的上下文让模型更好地理解问题并输出上下文。

User PromptExample
任务说明“写一封信跟老师说 meeting 要请假”
详细指引(optional)“开头先道歉,然后说明迟到理由(因为身体不适),最后说之后再找时间跟老师更新进度”
额外条件“100 字以内”
输出风格“非常严肃”
项目System Prompt(系统提示)User Prompt(用户提示)
定义模型的行为规范或角色设定用户提出的具体问题或任务
作用决定模型的语气、风格、角色和回答范围决定模型需要生成的具体内容
谁设置系统或开发者用户
用户可见性一般不可见用户直接输入,可随时修改
示例“你是一个专业的前端工程师,请用简明易懂的方式回答技术问题。”“帮我写一段 Python 代码,实现快速排序。”
特点持续影响对话中的所有回答每次对话输入只影响当前轮回答
项目Dialogue History(对话历史)Long-term Memory(长期记忆)
定义模型当前对话会话中已经发生的所有交流记录模型跨会话、长期保存的用户信息或偏好
作用提供上下文,使模型能理解前文内容、延续对话逻辑保留用户偏好、长期信息,实现个性化或持续性互动
存储时间临时,仅在当前会话有效长期,可跨多个会话使用
内容类型前几轮的 System prompt、User prompt 和模型的回答用户资料、兴趣偏好、历史问题、长期项目数据等
示例对话中用户问过的问题、模型的回答用户喜欢的语言风格、常问的技术领域、项目偏好
特点用于维持对话连贯性和上下文理解用于长期个性化和记忆追踪,可以影响未来对话

(让 LLM 调用工具的一种方法)用一些特殊的 token 表示语言模型使用相关工具,将工具返回的结果整合得到最终的结果。

webp

完整描述上下文的 token 通常很多,容易干扰到模型的判断,Context Engineering 可以将需要的信息从中过滤出来。常用方法:

webp

代码

初始化:

python
from transformers import pipeline
import json
import torch
from huggingface_hub import login
 
login(token="hf_LXXXV", new_session=False)
pipe = pipeline(
    "text-generation",
   "google/gemma-3-4b-it"
)

定义乘和除工具:

python
def multiply(a, b):
  return a * b
 
def devide(a, b):
  return a / b
webp

使用工具:

python
tool_use = """
      有必要可以使用工具,每一個工具都是函式。
      使用工具的方式為輸出 "<tool>[使用工具指令]</tool>"。
      你會得到回傳結果 "<tool_output>[工具回傳的結果]</tool_output>"。
      如果有使用工具的話,你應該告訴使用者工具回傳的結果。
 
      可用工具:
      multiply(a,b): 回傳 a 乘以 b
      devide(a,b): 回傳 a 除以 b
      """
 
user_input = "111 x 222 / 777 =? " #正確答案是 31.71428...
# user_input = "你好嗎?"
 
messages = [
             {
        "role": "system",
        "content": [
            {"type": "text", "text": tool_use}
        ]
    },
                   {
        "role": "user",
        "content": [
            {"type": "text", "text": user_input}
        ]
    }
]
 
while True:
 
  outputs = pipe(messages, max_new_tokens=1000) #跑語言模型
 
  response = outputs[0]["generated_text"][-1]['content'] #語言模型實際的輸出
 
  if ("</tool>" in response): #如果輸出有要「使用工具」,我們需要剖析語言模型要用甚麼工具,並且幫忙執行工具
    commend = response.split("<tool>")[1].split("</tool>")[0] #從字串 response 中,抓取第一個 <tool> 和 </tool> 之間的內容,並把它存到變數 commend 裡
    print("呼叫工具:", commend)
    tool_output = str(eval(commend)) #eval(commend) 才能真的去執行 commend 這段程式碼
    print("工具回傳:", tool_output)
 
    response  =  response.split("</tool>")[0] + "</tool>" #把</tool>之後的內容截掉
    messages.append(      {
        "role": "assistant",
        "content": [
            {"type": "text", "text": response} #使用工具
        ]
    }
    )
 
    output = "<tool_output>" + tool_output + "</tool_output>"   #加入把工具執行結果
    messages.append(      {
        "role": "user",
        "content": [
            {"type": "text", "text": output} #工具回傳
        ]
    }
    )
  else:
    print("最终輸出:", response)
    break
呼叫工具: multiply(111, 222)
工具回傳: 24642
呼叫工具: devide(24642, 777)
工具回傳: 31.714285714285715
最终輸出: 111 x 222 / 777 = 31.714285714285715
Mermaid
Loading diagram…
python
def get_temperature(city,time):
  return city + "在" + time + "的氣溫是攝氏 30000000000 度"
 
tool_use = """
      有必要可以使用工具,每一個工具都是函式。
      使用工具的方式為輸出 "<tool>[使用工具指令]</tool>"。
      你會得到回傳結果 "<tool_output>[工具回傳的結果]</tool_output>"。
      如果有使用工具的話,你應該告訴使用者工具回傳的結果。
 
      可用工具:
      multiply(a,b): 回傳 a 乘以 b
      devide(a,b): 回傳 a 除以 b
      get_temperature(city,time): 回傳 city 在 time 的氣溫,注意 city 和 time 都是字串
      """
 
#user_input = "111 x 222 / 777 =? " #正確答案是 31.71428...
#user_input = "你好嗎?"
user_input = "告訴我长崎 12/32 天氣如何啊?"
 
messages = [
             {
        "role": "system",
        "content": [
            {"type": "text", "text": tool_use}
        ]
    },
                   {
        "role": "user",
        "content": [
            {"type": "text", "text": user_input}
        ]
    }
]
 
while True:
 
  outputs = pipe(messages, max_new_tokens=1000) #跑語言模型
 
  response = outputs[0]["generated_text"][-1]['content'] #語言模型實際的輸出
 
  if ("</tool>" in response): #如果輸出有要「使用工具」,我們需要剖析語言模型要用甚麼工具,並且幫忙執行工具
    commend = response.split("<tool>")[1].split("</tool>")[0] #從字串 response 中,抓取第一個 <tool> 和 </tool> 之間的內容,並把它存到變數 commend 裡
    print("呼叫工具:", commend)
    tool_output = str(eval(commend)) #eval(commend) 才能真的去執行 commend 這段程式碼
    print("工具回傳:", tool_output)
 
    response  =  response.split("</tool>")[0] + "</tool>" #把</tool>之後的內容截掉
    messages.append(      {
        "role": "assistant",
        "content": [
            {"type": "text", "text": response} #使用工具
        ]
    }
    )
 
    output = "<tool_output>" + tool_output + "</tool_output>"   #加入把工具執行結果
    messages.append(      {
        "role": "user",
        "content": [
            {"type": "text", "text": output} #工具回傳
        ]
    }
    )
  else:
    print("LLM的輸出(不顯示使用工具的過程):", response)
    break
呼叫工具: get_temperature(city="長崎", time="12/32")
工具回傳: 長崎在12/32的氣溫是攝氏 30000000000 度
LLM的輸出(不顯示使用工具的過程): 哇,長崎12/32的天氣非常熱! 攝氏30000000000度!