大模型RAG与Agent学习笔记

33 阅读7分钟

【一】大模型调用及相关准备

1.使用阿里云百炼的模型

image.png

image.png

image.png

2.使用Ollama进行本地模型部署

简单说:在自己电脑上部署和运行大模型,由自己电脑的硬件提供算力支撑模型的运行,所以不需要像阿里云百炼那样担心自己Token不够用,消耗的只是自己的电力。
(可能会有点慢,要根据自己电脑的显卡性能选择合适的参数;不是标准的大模型【蒸馏模型】)

image.png

image.png

3.OpenAI大致使用流程

image.png

4.OpenAI的流式输出

目的:使用户获得更好的使用体验

image.png

image.png

5.OpenAI附带历史消息调用模型

image.png (这种方式太落后了,看看得了)

【二】提示词优化工程

image.png

image.png

image.png 提示:"ensure_ascii=False" 避免中文错误
代码示例:采用Few-shot提示词优化:

from openai import OpenAI
import json
client = OpenAI(
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"

)
schema = ['日期', '股票名称', '开盘价', '收盘价', '成交量']
examples_data = [       # 示例数据
    {
        "content": "2023-01-10,股市震荡。股票强大科技A股今日开盘价100人民币,一度飙升至105人民币,随后回落至98人民币,最终以102人民币收盘,成交量达到520000。",
        "answers": {
            "日期": "2023-01-10",
            "股票名称": "强大科技A股",
            "开盘价": "100人民币",
            "收盘价": "102人民币",
            "成交量": "520000"
        }
    },
    {
        "content": "2024-05-16,股市利好。股票英伟达美股今日开盘价105美元,一度飙升至109美元,随后回落至100美元,最终以116美元收盘,成交量达到3560000。",
        "answers": {
            "日期": "2024-05-16",
            "股票名称": "英伟达美股",
            "开盘价": "105美元",
            "收盘价": "116美元",
            "成交量": "3560000"
        }
    }
]
questions = [       # 提问问题
    "2025-06-16,股市利好。股票传智教育A股今日开盘价66人民币,一度飙升至70人民币,随后回落至65人民币,最终以68人民币收盘,成交量达到123000。",
    "2025-06-06,股市利好。股票黑马程序员A股今日开盘价200人民币,一度飙升至211人民币,随后回落至201人民币,最终以206人民币收盘。"
]
messages = [
    {"role": "system",      "content": f"你帮我完成信息抽取,我给你句子,你抽取{schema}信息,按JSON字符串输出,如果某些信息不存在,用'原文未提及'表示,请参考如下示例:"}
]
for example in examples_data:
    messages.append(
        {"role": "user", "content": example["content"]}
    )
    messages.append(
        {"role": "assistant", "content": json.dumps(example["answers"], ensure_ascii=False)}
    )
for q in questions:
    response = client.chat.completions.create(
        model="deepseek-v3",
        messages=messages + [{"role": "user", "content": f"按照上述的示例,现在抽取这个句子的信息:{q}"}]
    )
    print(response.choices[0].message.content)

37行-43行是整理提示词数据,只输出整理结果就为:

[
    {"role": "system",      "content": f"你帮我完成信息抽取,我给你句子,你抽取{schema}信息,按JSON字符串输出,如果某些信息不存在,用'原文未提及'表示,请参考如下示例:"},

    {"role": "user",        "content": "2023-01-10,股市震荡。股票强大科技A股今日开盘价100人民币,一度飙升至105人民币,随后回落至98人民币,最终以102人民币收盘,成交量达到520000。"},
    {"role": "assistant",   "content": '{"日期":"2023-01-10","股票名称":"强大科技A股","开盘价":"100人民币","收盘价":"102人民币","成交量":"520000"}'},
    {"role": "user",        "content": "2024-05-16,股市利好。股票英伟达美股今日开盘价105美元,一度飙升至109美元,随后回落至100美元,最终以116美元收盘,成交量达到3560000。"},
    {"role": "assistant",   "content": '{"日期":"2024-05-16","股票名称":"英伟达美股","开盘价":"105美元","收盘价":"116美元","成交量":"3560000"}'},

    {"role": "user",        "content": f"按照上述示例,现在抽取这个句子的信息:{要抽取的句子文本}"}]}
]

【三】RAG开发-LangChain

1.LangChain

image.png

image.png

2.RAG介绍

RAG核心工作的的两个流程: image.png

image.png

向量的基础概念:

image.png

扩展:余弦相似度计算:

image.png 代码:

import numpy as np
"""
计算两个向量的余弦相似度(衡量方向相似性,剔除长度影响)
参数:
    vec_a (np.array): 向量A
    vec_b (np.array): 向量B
返回:
    float: 余弦相似度结果(范围[-1,1],越接近1方向越一致)
公式:
    cos_sim = (vec_a · vec_b) / (||vec_a|| × ||vec_b||)
    拆解:
    1. 点积:vec_a · vec_b = vec_a[0]×vec_b[0] + vec_a[1]×vec_b[1] + ... + vec_a[n]×vec_b[n]
    2. 模长:||vec_a|| = √(vec_a[0]² + vec_a[1]² + ... + vec_a[n]²)
    3. 模长:||vec_b|| = √(vec_b[0]² + vec_b[1]² + ... + vec_b[n]²)
A: [0.5, 0.5]
B: [0.7, 0.7]
C: [0.7, 0.5]
D: [-0.6, -0.5]
"""
def get_dot(vec_a, vec_b):
    """计算2个向量的点积,2个向量同维度数字乘积之和"""
    if len(vec_a) != len(vec_b):
        raise ValueError("2个向量必须维度数量相同")
    dot_sum = 0
    for a, b in zip(vec_a, vec_b):
        dot_sum += a * b
    return dot_sum
def get_norm(vec):
    """计算单个向量的模长:对向量的每个数字求平方在求和在开根号"""
    sum_square = 0
    for v in vec:
        sum_square += v * v
    # numpy sqrt函数完成开根号
    return np.sqrt(sum_square)
def cosine_similarity(vec_a, vec_b):
    """余弦相似度:2个向量的点积 除以 2个向量模长的乘积"""
    result = get_dot(vec_a, vec_b) / (get_norm(vec_a) * get_norm(vec_b))
    return result
if __name__ == '__main__':
    vec_a = [0.5, 0.5]
    vec_b = [0.7, 0.7]
    vec_c = [0.7, 0.5]
    vec_d = [-0.6, -0.5]

    print("ab:", cosine_similarity(vec_a, vec_b))
    print("ac:", cosine_similarity(vec_a, vec_c))
    print("ad:", cosine_similarity(vec_a, vec_d))
3.LangChain调用大语言模型
# langchain_community
from langchain_community.llms.tongyi import Tongyi

# 不用qwen3-max,因为qwen3-max是聊天模型,qwen-max是大语言模型
model = Tongyi(model="qwen-max")

# 调用invoke向模型提问
res = model.invoke(input="你是谁呀能做什么?")

print(res)
4.LangChain模型流式输出(用Ollama版)
from langchain_ollama import OllamaLLM

model = OllamaLLM(model="qwen3:4b")

res = model.stream(input="你是谁呀能做什么?")

for chunk in res:
    print(chunk, end="", flush=True)
5.LangChain调用聊天模型

image.png

image.png

6.LangChain消息的简化升级

下面的内容被替换成了元组形式

# 准备消息列表
messages = [
    # (角色,内容)  角色:system/human/ai
    ("system", "你是一个边塞诗人。"),
    ("human", "写一首唐诗。"),
    ("ai", "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦。"),
    ("human", "按照你上一个回复的格式,在写一首唐诗。")
]

前一种调用方式是静态的,这一种方式是动态的
所以此方式有一个好处:支持内部填充{变量}占位

image.png

7.LangChain调用文本嵌入模型(文本向量化)

image.png

8.zero-shot提示词模板
from langchain_core.prompts import PromptTemplate
from langchain_community.llms.tongyi import Tongyi

prompt_template = PromptTemplate.from_template(
    "我的邻居姓{lastname}, 刚生了{gender}, 你帮我起个名字,简单回答。"
)
model = Tongyi(model="qwen-max")

chain = prompt_template | model
res = chain.invoke(input={"lastname": "张", "gender": "女儿"})
print(res)

image.png

9.FewShot提示词模板

image.png 代码示例:

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_community.llms.tongyi import Tongyi

# 示例的模板
example_template = PromptTemplate.from_template("单词:{word}, 反义词:{antonym}")

# 示例的动态数据注入 要求是list内部套字典
examples_data = [
    {"word": "大", "antonym": "小"},
    {"word": "上", "antonym": "下"},
]

few_shot_template = FewShotPromptTemplate(
    example_prompt=example_template,    # 示例数据的模板
    examples=examples_data,             # 示例的数据(用来注入动态数据的),list内套字典
    prefix="告知我单词的反义词,我提供如下的示例:",                   # 示例之前的提示词
    suffix="基于前面的示例告知我,{input_word}的反义词是?",          # 示例之后的提示词
    input_variables=['input_word']      # 声明在前缀或后缀中所需要注入的变量名
)

prompt_text = few_shot_template.invoke(input={"input_word": "左"}).to_string()
print(prompt_text)

model = Tongyi(model="qwen-max")

print(model.invoke(input=prompt_text))
10.format和invoke区别

image.png 代码示例

template = PromptTemplate.from_template("我的邻居是:{lastname},最喜欢:{hobby}")

res = template.format(lastname="张大明", hobby="钓鱼")
print(res, type(res))


res2 = template.invoke({"lastname": "周杰轮", "hobby": "唱歌"})
print(res2, type(res2))

输出结果:

image.png

11.ChatPromptTemplate的使用

image.png

image.png

代码示例: image.png

12.Chain的基础使用

image.png 代码实例:

model = ChatTongyi(model="qwen3-max")

# 组成链,要求每一个组件都是Runnable接口的子类
chain = chat_prompt_template | model

# 通过stream流式输出
for chunk in chain.stream({"history": history_data}):
    print(chunk.content, end="", flush=True)

image.png

image.png

13.StrOutputParse字符串输出解析器

image.png

image.png 第一个model的输出是AIMessage,是没法作为输入给第二个model的。所以得将AIMessage类型转化成基础字符串,具体表现为:加入parser这个组件。
代码实例:

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_community.chat_models.tongyi import ChatTongyi

parser = StrOutputParser()
model = ChatTongyi(model="qwen3-max")
prompt = PromptTemplate.from_template(
    "我邻居姓:{lastname},刚生了{gender},请起名,仅告知我名字无需其它内容。"
)

chain = prompt | model | parser | model

res: str = chain.invoke({"lastname": "张", "gender": "女儿"})
print(res)

【四】RAG项目

【五】Agent智能体