Compare commits

7 Commits

Author SHA1 Message Date
ebf333cabf 20251025 2025-10-25 21:14:41 +08:00
0fb54e8a95 20250912 2025-09-12 23:56:37 +08:00
46694bfb5b 设置代理方法 2025-08-27 23:03:35 +08:00
e5362b80e2 save all 2025-08-27 22:22:18 +08:00
f6c7c65d6c save all 2025-08-27 22:21:14 +08:00
75ae2c5fd5 llama_index的starter.py能跑起来了 2025-08-27 22:20:51 +08:00
b35e44f27d init 2025-08-22 23:56:59 +08:00
55 changed files with 3274 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea
knightutils.egg-info

View File

View File

@@ -0,0 +1,142 @@
"""
Python中设置代理的完整示例
"""
import os
import requests
import urllib.request
from urllib.parse import urlparse
def set_global_proxy(proxy_url):
"""
为整个Python进程设置全局代理
Args:
proxy_url (str): 代理地址,例如 "http://proxy.example.com:8080"
"socks5://127.0.0.1:1080"
"""
# 解析代理URL
parsed = urlparse(proxy_url)
proxy_address = f"{parsed.scheme}://{parsed.hostname}:{parsed.port}"
# 设置环境变量影响urllib、requests等库
os.environ['http_proxy'] = proxy_address
os.environ['https_proxy'] = proxy_address
# 有些库可能使用大写环境变量
os.environ['HTTP_PROXY'] = proxy_address
os.environ['HTTPS_PROXY'] = proxy_address
print(f"已设置全局代理: {proxy_address}")
def set_requests_proxy(proxy_url, username=None, password=None):
"""
仅为requests库设置代理
Args:
proxy_url (str): 代理地址
username (str, optional): 代理用户名
password (str, optional): 代理密码
Returns:
dict: 可直接用于requests的代理字典
"""
if username and password:
# 添加认证信息
parsed = urlparse(proxy_url)
proxy_with_auth = f"{parsed.scheme}://{username}:{password}@{parsed.hostname}:{parsed.port}"
proxies = {
'http': proxy_with_auth,
'https': proxy_with_auth
}
else:
proxies = {
'http': proxy_url,
'https': proxy_url
}
print(f"已为requests设置代理: {proxy_url}")
return proxies
def test_proxy_connection(test_url="https://httpbin.org/ip", proxies=None):
"""
测试代理连接
Args:
test_url (str): 测试URL
proxies (dict, optional): 代理设置
"""
try:
if proxies:
response = requests.get(test_url, proxies=proxies, timeout=10)
else:
response = requests.get(test_url, timeout=10)
print(f"代理测试成功IP信息: {response.json()}")
return True
except Exception as e:
print(f"代理测试失败: {e}")
return False
def clear_proxy():
"""
清除代理设置
"""
for var in ['http_proxy', 'https_proxy', 'HTTP_PROXY', 'HTTPS_PROXY']:
if var in os.environ:
del os.environ[var]
print("已清除代理设置")
def example_with_requests():
"""
使用requests库通过代理访问网络的示例
"""
print("\n=== Requests代理示例 ===")
# 不使用代理
print("不使用代理:")
test_proxy_connection()
# 使用代理(示例地址,请替换为实际代理地址)
print("\n使用代理:")
proxies = set_requests_proxy("http://proxy.example.com:8080")
# test_proxy_connection(proxies=proxies) # 取消注释并替换为实际代理地址进行测试
def example_with_global_proxy():
"""
设置全局代理的示例
"""
print("\n=== 全局代理示例 ===")
# 设置全局代理
set_global_proxy("http://proxy.example.com:8080")
# 测试连接
test_proxy_connection()
# 清除代理
clear_proxy()
if __name__ == "__main__":
print("Python代理设置完整示例")
print("=" * 40)
# 示例1: 使用requests设置代理
example_with_requests()
# 示例2: 设置全局代理
example_with_global_proxy()
print("\n代理设置说明:")
print("1. 环境变量方法影响整个Python进程")
print("2. requests代理方法仅影响使用requests的请求")
print("3. 实际使用时请替换示例代理地址为真实地址")
print("4. SOCKS代理需要安装: pip install requests[socks]")

View File

@@ -0,0 +1,103 @@
"""
演示在Python中设置代理的几种方法
"""
import os
import requests
from urllib.request import ProxyHandler, build_opener
fiddler_proxy = 'http://localhost:8866'
fiddlers_proxy = 'http://localhost:8866'
proxy = fiddler_proxy
proxys = fiddlers_proxy
def set_proxy_with_os():
"""
方法1: 使用环境变量设置代理
这种方法会影响整个Python进程的网络请求
"""
# 设置HTTP代理
os.environ['http_proxy'] = proxy
os.environ['https_proxy'] = proxys
# 如果需要身份验证
# os.environ['http_proxy'] = 'http://username:password@proxy.example.com:8080'
# os.environ['https_proxy'] = 'http://username:password@proxy.example.com:8080'
print("已通过环境变量设置代理")
def set_proxy_with_requests():
"""
方法2: 使用requests库单独设置代理
这种方法只影响使用requests的请求
"""
proxies = {
'http': proxy,
'https': proxys
}
# 如果需要身份验证
# proxies = {
# 'http': 'http://username:password@proxy.example.com:8080',
# 'https': 'http://username:password@proxy.example.com:8080'
# }
try:
response = requests.get('https://httpbin.org/ip', proxies=proxies, timeout=10)
print(f"通过代理访问的结果: {response.json()}")
except Exception as e:
print(f"使用requests通过代理访问出错: {e}")
def set_proxy_with_urllib():
"""
方法3: 使用urllib设置代理
"""
proxy_handler = ProxyHandler({
'http': proxy,
'https': proxys
})
opener = build_opener(proxy_handler)
try:
response = opener.open('https://httpbin.org/ip', timeout=10)
print(f"通过urllib代理访问的结果: {response.read().decode()}")
except Exception as e:
print(f"使用urllib通过代理访问出错: {e}")
def unset_proxy():
"""
取消代理设置
"""
if 'http_proxy' in os.environ:
del os.environ['http_proxy']
if 'https_proxy' in os.environ:
del os.environ['https_proxy']
if 'HTTP_PROXY' in os.environ:
del os.environ['HTTP_PROXY']
if 'HTTPS_PROXY' in os.environ:
del os.environ['HTTPS_PROXY']
print("已取消代理设置")
if __name__ == "__main__":
print("Python代理设置演示")
print("=" * 30)
# 演示设置代理
set_proxy_with_os()
# 演示使用requests通过代理访问
set_proxy_with_requests()
# 演示使用urllib通过代理访问
set_proxy_with_urllib()
# 取消代理设置
unset_proxy()

View File

@@ -0,0 +1,28 @@
from llama_index.core import SimpleDirectoryReader
from llama_index.readers.dashscope.base import DashScopeParse
from llama_index.readers.dashscope.utils import ResultType
from llama_index.indices.managed.dashscope import DashScopeCloudIndex
def read_parse_upload_local_documents(dir, num_workers=1):
"""读取、解析、上传本地文件到百炼数据管理平台。
Args:
dir (str): 本地文件存储的路径。
num_workers (int, optional): 执行的并发数。
Returns:
已上传到云端的文件列表
"""
parse = DashScopeParse(result_type=ResultType.DASHSCOPE_DOCMIND)
file_extractor = {'.txt': parse, '.docx': parse, ".pdf": parse} # 设置需要读取解析的文件格式,请根据实际需求调整
documents = SimpleDirectoryReader(input_dir=dir, file_extractor=file_extractor).load_data(num_workers=num_workers)
return documents
if __name__ == '__main__':
dir = "./docs/" # 本例中业务相关文件存储在当前路径下的docs文件夹请根据实际情况调整。
documents = read_parse_upload_local_documents(dir)
cloud_index_name = "my_first_index" # 设置云端知识库索引名称
index = DashScopeCloudIndex.from_documents(documents, cloud_index_name, verbose=True) # 创建云端知识库索引

View File

@@ -0,0 +1,11 @@
百炼系列智能音箱产品介绍
踏入智能家居的核心地带,百炼智能音箱系列以其创新设计与智能交互技术,重新定义家庭生活的每一个角落。
百炼EchoSphere S1 —— 智慧家居的指挥官: 设计简约而不失时尚采用360度全向发声技术配备高端音频单元提供深沉低音与清澈高音的完美平衡。支持Wi-Fi与蓝牙5.0双连接轻松接入您的智能家居生态。内置智能语音助手只需一声令下即可控制家中电器、查询天气、播放音乐等。长达20小时的续航能力让音乐与便利伴您一整天。参考售价999 - 1299。
通义VoiceBox V7 —— 生活小秘书: 采用8个远场麦克风阵列即使在嘈杂环境中也能精准识别您的指令。拥有7英寸触摸屏不仅能听更能看查看菜谱、视频通话、浏览新闻一应俱全。4GB内存与64GB存储空间存储您喜爱的歌曲与节目。内置电池支持8小时连续使用从厨房到卧室随心移动。参考售价1499 - 1799。
星尘SoundWave SW Pro —— 音乐发烧友的选择: 采用HiFi级音频解码芯片支持aptX HD与LDAC高品质音频传输还原录音室级别的音质。独特的声学结构设计带来震撼的3D环绕声效果。12GB RAM与256GB存储存储海量音乐资源。AI音效调节根据环境自动优化音质。内置电池续航高达12小时户外派对也能尽兴。参考售价2999 - 3499。
百炼SmartHalo H1 —— 家庭互动的中心: 独特的环形灯效设计不仅是一款音箱更是家居装饰的艺术品。支持多种语音助手兼容iOS与Android系统家庭成员均可个性化设置。内置丰富的儿童教育资源成为孩子成长的好伙伴。5000mAh电池满足全家人的日常使用需求。参考售价1299 - 1599。
百炼MiniBoom MB Plus —— 便携式智能乐趣: 极致小巧仅手掌大小却拥有令人惊喜的音质表现。IP67防水防尘设计无论户外探险还是浴室放松都能陪伴左右。支持语音控制与触控操作内置电池续航达10小时。无线串联功能轻松构建环绕立体声场。参考售价299 - 399。
每一款百炼智能音箱都是对智能生活美学的诠释,旨在为您的家庭带来前所未有的便捷与愉悦。选择百炼,让智能生活的声音更加悦耳动听。

View File

@@ -0,0 +1,57 @@
from llama_index.core import Settings
from llama_index.llms.dashscope import DashScope
from llama_index.indices.managed.dashscope import DashScopeCloudIndex
from llama_index.core.postprocessor import SimilarityPostprocessor
from llama_index.postprocessor.dashscope_rerank import DashScopeRerank
'''
本例中构建检索引擎时,需要手动设置下列参数,请根据实际效果调整。
'''
Settings.llm = DashScope(model_name="qwen-max") # 设置检索引擎生成回答时调用的大模型。
similarity_top_k = 5 # 检索引擎找到的相似度最高的结果数
similarity_cutoff = 0.4 # 过滤检索结果时使用的最低相似度阈值
top_n = 1 # 进行重排后返回语义上相关度最高的结果数
'''
本例中构建RAG应用时设置如下问答模板请根据实际需求调整。
'''
init_chat = "\n您好我是AI助手可以回答关于百炼系列产品的提问。有什么可以帮您的请输入问题退出请输入'q'\n> "
resp_with_no_answer = "很抱歉,知识库未提供相关信息。" + "\n"
prompt_template = "回答如下问题: {0}\n如果根据提供的信息无法回答,请返回:{1}"
'''
格式化输出。
'''
def prettify_rag(resp):
output = ""
output += "\n回答:{0}\n".format(resp.response)
for j in range(len(resp.source_nodes)):
output += "\n产品知识库中的相关文本:\n{0}\n".format(resp.source_nodes[j].text)
return output
'''
基于云端知识库的向量索引,构建检索引擎,能够接收终端用户的提问,从云端知识库中检索相关的文本片段,再将提问和检索结果合并后输入到大模型,并生成回答。
RAG应用提供与终端用户的交互界面如果无法检索到相关的文本片段或根据检索到的文本片段无法回答终端用户的提问则返回适当的错误信息。
'''
if __name__ == '__main__':
index = DashScopeCloudIndex("my_first_index") # 读取百炼平台上已创建的知识库索引
query_engine = index.as_query_engine( # 构建检索引擎
similarity_top_k=similarity_top_k,
node_postprocessors=[ # 默认检索结果可能不满足需求本例中通过加入node_postprocessors对检索结果进行后处理。
SimilarityPostprocessor(similarity_cutoff=similarity_cutoff), # 过滤不满足最低相似度阈值的检索结果。
DashScopeRerank(top_n=top_n, model="gte-rerank") # 对检索结果进行重排,返回语义上相关度最高的结果。
],
response_mode="tree_summarize"
)
while True:
user_prompt = input(init_chat)
if user_prompt in ['q','Q']:
break
resp = query_engine.query(prompt_template.format(user_prompt, resp_with_no_answer))
if len(resp.source_nodes) == 0:
output = resp_with_no_answer # 如果未找到相关上下文信息,则返回适当的报错信息。
else:
output = prettify_rag(resp)
print(output)

View File

@@ -0,0 +1,12 @@
llama-index==0.10.65
dashscope==1.20.4
llama-index-embeddings-dashscope==0.1.4
llama-index-indices-managed-llama-cloud==0.2.7
llama-index-llms-dashscope==0.1.2
llama-index-node-parser-dashscope==0.1.2
llama-index-postprocessor-dashscope-rerank==0.1.4
llama-index-readers-dashscope==0.1.2
llama-index-readers-file==0.1.33
llama-index-readers-llama-parse==0.1.6
llama-parse==0.4.9
llama-index-indices-managed-dashscope==0.1.2

2
local_rag/README.md Normal file
View File

@@ -0,0 +1,2 @@
Run: uvicorn main:app --port 7866
Then visit 127.0.0.1:7866

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"graph_dict": {}}

View File

@@ -0,0 +1 @@
{"embedding_dict": {}, "text_id_to_ref_doc_id": {}, "metadata_dict": {}}

View File

@@ -0,0 +1 @@
{"index_store/data": {"ab9a86f4-0029-48e5-b823-eccfc6f58622": {"__type__": "vector_store", "__data__": "{\"index_id\": \"ab9a86f4-0029-48e5-b823-eccfc6f58622\", \"summary\": null, \"nodes_dict\": {\"c7e14d46-b930-4a98-acaf-2854ac14c1de\": \"c7e14d46-b930-4a98-acaf-2854ac14c1de\", \"fb1f2a38-146e-4840-8f0d-221033dbc849\": \"fb1f2a38-146e-4840-8f0d-221033dbc849\"}, \"doc_id_dict\": {}, \"embeddings_dict\": {}}"}}}

93
local_rag/chat.py Normal file
View File

@@ -0,0 +1,93 @@
import os
from openai import OpenAI
from llama_index.core import StorageContext,load_index_from_storage,Settings
from llama_index.embeddings.dashscope import (
DashScopeEmbedding,
DashScopeTextEmbeddingModels,
DashScopeTextEmbeddingType,
)
from llama_index.postprocessor.dashscope_rerank import DashScopeRerank
from create_kb import *
DB_PATH = "VectorStore"
TMP_NAME = "tmp_abcd"
EMBED_MODEL = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2,
text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT,
)
# 若使用本地嵌入模型,请取消以下注释:
# from langchain_community.embeddings import ModelScopeEmbeddings
# from llama_index.embeddings.langchain import LangchainEmbedding
# embeddings = ModelScopeEmbeddings(model_id="modelscope/iic/nlp_gte_sentence-embedding_chinese-large")
# EMBED_MODEL = LangchainEmbedding(embeddings)
# 设置嵌入模型
Settings.embed_model = EMBED_MODEL
def get_model_response(multi_modal_input,history,model,temperature,max_tokens,history_round,db_name,similarity_threshold,chunk_cnt):
# prompt = multi_modal_input['text']
prompt = history[-1][0]
tmp_files = multi_modal_input['files']
if os.path.exists(os.path.join("File",TMP_NAME)):
db_name = TMP_NAME
else:
if tmp_files:
create_tmp_kb(tmp_files)
db_name = TMP_NAME
# 获取index
print(f"prompt:{prompt},tmp_files:{tmp_files},db_name:{db_name}")
try:
dashscope_rerank = DashScopeRerank(top_n=chunk_cnt,return_documents=True)
storage_context = StorageContext.from_defaults(
persist_dir=os.path.join(DB_PATH,db_name)
)
index = load_index_from_storage(storage_context)
print("index获取完成")
retriever_engine = index.as_retriever(
similarity_top_k=20,
)
# 获取chunk
retrieve_chunk = retriever_engine.retrieve(prompt)
print(f"原始chunk为{retrieve_chunk}")
try:
results = dashscope_rerank.postprocess_nodes(retrieve_chunk, query_str=prompt)
print(f"rerank成功重排后的chunk为{results}")
except:
results = retrieve_chunk[:chunk_cnt]
print(f"rerank失败chunk为{results}")
chunk_text = ""
chunk_show = ""
for i in range(len(results)):
if results[i].score >= similarity_threshold:
chunk_text = chunk_text + f"## {i+1}:\n {results[i].text}\n"
chunk_show = chunk_show + f"## {i+1}:\n {results[i].text}\nscore: {round(results[i].score,2)}\n"
print(f"已获取chunk{chunk_text}")
prompt_template = f"请参考以下内容:{chunk_text},以合适的语气回答用户的问题:{prompt}。如果参考内容中有图片链接也请直接返回。"
except Exception as e:
print(f"异常信息:{e}")
prompt_template = prompt
chunk_show = ""
history[-1][-1] = ""
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
system_message = {'role': 'system', 'content': 'You are a helpful assistant.'}
messages = []
history_round = min(len(history),history_round)
for i in range(history_round):
messages.append({'role': 'user', 'content': history[-history_round+i][0]})
messages.append({'role': 'assistant', 'content': history[-history_round+i][1]})
messages.append({'role': 'user', 'content': prompt_template})
messages = [system_message] + messages
completion = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens,
stream=True
)
assistant_response = ""
for chunk in completion:
assistant_response += chunk.choices[0].delta.content
history[-1][-1] = assistant_response
yield history,chunk_show

134
local_rag/create_kb.py Normal file
View File

@@ -0,0 +1,134 @@
#####################################
###### 创建知识库 #######
#####################################
import gradio as gr
import os
import shutil
from llama_index.core import VectorStoreIndex,Settings,SimpleDirectoryReader
from llama_index.embeddings.dashscope import (
DashScopeEmbedding,
DashScopeTextEmbeddingModels,
DashScopeTextEmbeddingType,
)
from llama_index.core.schema import TextNode
from upload_file import *
DB_PATH = "VectorStore"
STRUCTURED_FILE_PATH = "File/Structured"
UNSTRUCTURED_FILE_PATH = "File/Unstructured"
TMP_NAME = "tmp_abcd"
EMBED_MODEL = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2,
text_type=DashScopeTextEmbeddingType.TEXT_TYPE_DOCUMENT,
)
# 若使用本地嵌入模型,请取消以下注释:
# from langchain_community.embeddings import ModelScopeEmbeddings
# from llama_index.embeddings.langchain import LangchainEmbedding
# embeddings = ModelScopeEmbeddings(model_id="modelscope/iic/nlp_gte_sentence-embedding_chinese-large")
# EMBED_MODEL = LangchainEmbedding(embeddings)
# 设置嵌入模型
Settings.embed_model = EMBED_MODEL
# 刷新知识库
def refresh_knowledge_base():
return os.listdir(DB_PATH)
# 创建非结构化向量数据库
def create_unstructured_db(db_name:str,label_name:list):
print(f"知识库名称为:{db_name},类目名称为:{label_name}")
if label_name is None:
gr.Info("没有选择类目")
elif len(db_name) == 0:
gr.Info("没有命名知识库")
# 判断是否存在同名向量数据库
elif db_name in os.listdir(DB_PATH):
gr.Info("知识库已存在,请换个名字或删除原来知识库再创建")
else:
gr.Info("正在创建知识库请等待知识库创建成功信息显示后前往RAG问答")
documents = []
for label in label_name:
label_path = os.path.join(UNSTRUCTURED_FILE_PATH,label)
documents.extend(SimpleDirectoryReader(label_path).load_data())
index = VectorStoreIndex.from_documents(
documents
)
db_path = os.path.join(DB_PATH,db_name)
if not os.path.exists(db_path):
os.mkdir(db_path)
index.storage_context.persist(db_path)
elif os.path.exists(db_path):
pass
gr.Info("知识库创建成功可前往RAG问答进行提问")
# 创建结构化向量数据库
def create_structured_db(db_name:str,data_table:list):
print(f"知识库名称为:{db_name},数据表名称为:{data_table}")
if data_table is None:
gr.Info("没有选择数据表")
elif len(db_name) == 0:
gr.Info("没有命名知识库")
# 判断是否存在同名向量数据库
elif db_name in os.listdir(DB_PATH):
gr.Info("知识库已存在,请换个名字或删除原来知识库再创建")
else:
gr.Info("正在创建知识库请等待知识库创建成功信息显示后前往RAG问答")
documents = []
for label in data_table:
label_path = os.path.join(STRUCTURED_FILE_PATH,label)
documents.extend(SimpleDirectoryReader(label_path).load_data())
# index = VectorStoreIndex.from_documents(
# documents
# )
nodes = []
for doc in documents:
doc_content = doc.get_content().split('\n')
for chunk in doc_content:
node = TextNode(text=chunk)
node.metadata = {'source': doc.get_doc_id(),'file_name':doc.metadata['file_name']}
nodes = nodes + [node]
index = VectorStoreIndex(nodes)
db_path = os.path.join(DB_PATH,db_name)
if not os.path.exists(db_path):
os.mkdir(db_path)
index.storage_context.persist(db_path)
gr.Info("知识库创建成功可前往RAG问答进行提问")
# 删除指定名称知识库
def delete_db(db_name:str):
if db_name is not None:
folder_path = os.path.join(DB_PATH, db_name)
if os.path.exists(folder_path):
shutil.rmtree(folder_path)
gr.Info(f"已成功删除{db_name}知识库")
print(f"已成功删除{db_name}知识库")
else:
gr.Info(f"{db_name}知识库不存在")
print(f"{db_name}知识库不存在")
# 实时更新知识库列表
def update_knowledge_base():
return gr.update(choices=os.listdir(DB_PATH))
# 临时文件创建知识库
def create_tmp_kb(files):
if not os.path.exists(os.path.join("File",TMP_NAME)):
os.mkdir(os.path.join("File",TMP_NAME))
for file in files:
file_name = os.path.basename(file)
shutil.move(file,os.path.join("File",TMP_NAME,file_name))
documents = SimpleDirectoryReader(os.path.join("File",TMP_NAME)).load_data()
index = VectorStoreIndex.from_documents(
documents
)
db_path = os.path.join(DB_PATH,TMP_NAME)
if not os.path.exists(db_path):
os.mkdir(db_path)
index.storage_context.persist(db_path)
# 清除tmp文件夹下内容
def clear_tmp():
if os.path.exists(os.path.join("File",TMP_NAME)):
shutil.rmtree(os.path.join("File",TMP_NAME))
if os.path.exists(os.path.join(DB_PATH,TMP_NAME)):
shutil.rmtree(os.path.join(DB_PATH,TMP_NAME))

150
local_rag/html_string.py Normal file
View File

@@ -0,0 +1,150 @@
main_html = """<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>阿里云本地RAG解决方案</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
header {
background-color: #2196f3;
color: white;
width: 100%;
padding: 1.5em;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
main {
margin: 2em;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: white;
border-radius: 8px;
overflow: hidden;
width: 90%;
max-width: 800px;
padding: 2em;
}
h1 {
color: #333;
}
p {
color: #666;
font-size: 1.1em;
}
ul {
list-style-type: none;
padding: 0;
}
ul li {
background-color: #2196f3;
margin: 0.5em 0;
padding: 1em;
border-radius: 4px;
transition: background-color 0.3s;
}
ul li a {
color: white;
text-decoration: none;
display: flex;
align-items: center;
}
ul li:hover {
background-color: #1976d2;
}
.material-icons {
margin-right: 0.5em;
}
</style>
</head>
<body>
<header>
<h1>阿里云本地RAG解决方案</h1>
</header>
<main>
<p>如果您需要基于上传的文档与模型直接对话,请直接访问<a href="/chat">RAG问答</a>,并在输入框位置上传文件,就可以开始对话了。(此次上传的数据在页面刷新后无法保留,若您希望可以持久使用、维护知识库,请创建知识库)。</p>
<p>如果您需要创建或更新知识库,请按照<a href="/upload_data">上传数据</a>、<a href="/create_knowledge_base">创建知识库</a>操作,在<a href="/chat">RAG问答</a>中的“知识库选择”位置选择您需要使用的知识库。</p>
<p>如果您需要基于已创建好的知识库进行问答,请直接访问<a href="/chat">RAG问答</a>,在“加载知识库”处选择您已创建的知识库。</p>
<ul>
<li><a href="/upload_data"><span class="material-icons"></span> 1. 上传数据</a></li>
<li><a href="/create_knowledge_base"><span class="material-icons"></span> 2. 创建知识库</a></li>
<li><a href="/chat"><span class="material-icons"></span> 3. RAG问答</a></li>
</ul>
</main>
</body>
</html>"""
plain_html = """<!DOCTYPE html>
<html lang="zh">
<head>
<title>RAG问答</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
.links-container {
display: flex;
justify-content: center; /* 在容器中居中分布子元素 */
list-style-type: none; /* 去掉ul默认的列表样式 */
padding: 0; /* 去掉ul默认的内边距 */
margin: 0; /* 去掉ul默认的外边距 */
}
.links-container li {
margin: 0 5px; /* 每个li元素的左右留出一些空间 */
padding: 10px 15px; /* 添加内边距 */
border: 1px solid #ccc; /* 添加边框 */
border-radius: 5px; /* 添加圆角 */
background-color: #f9f9f9; /* 背景颜色 */
transition: background-color 0.3s; /* 背景颜色变化的过渡效果 */
display: flex; /* 使用flex布局 */
align-items: center; /* 垂直居中对齐 */
height: 50px; /* 设置固定高度,确保一致 */
}
.links-container li:hover {
background-color: #e0e0e0; /* 悬停时的背景颜色 */
}
.links-container a {
text-decoration: none !important; /* 去掉链接的下划线 */
color: #333; /* 链接颜色 */
font-family: Arial, sans-serif; /* 字体 */
font-size: 14px; /* 字体大小 */
display: flex; /* 使用flex布局 */
align-items: center; /* 垂直居中对齐 */
height: 100%; /* 确保链接高度与父元素一致 */
}
.material-icons {
font-size: 20px; /* 图标大小 */
margin-right: 8px; /* 图标和文字间的间距 */
text-decoration: none; /* 确保图标没有下划线 */
}
/* 深色模式样式 */
@media (prefers-color-scheme: dark) {
.links-container li {
background-color: #333; /* 深色模式下的背景颜色 */
border-color: #555; /* 深色模式下的边框颜色 */
}
.links-container li:hover {
background-color: #555; /* 深色模式下悬停时的背景颜色 */
}
.links-container a {
color: #f9f9f9; /* 深色模式下的文字颜色 */
}
}
</style>
</head>
<body>
<ul class="links-container">
<li><a href="/"><span class="material-icons">home</span> 主页</a></li>
<li><a href="/upload_data"><span class="material-icons">cloud_upload</span> 上传数据</a></li>
<li><a href="/create_knowledge_base"><span class="material-icons">library_add</span> 创建知识库</a></li>
<li><a href="/chat"><span class="material-icons">question_answer</span> RAG问答</a></li>
</ul>
</body>
</html>"""

BIN
local_rag/images/tongyi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
local_rag/images/user.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

116
local_rag/main.py Normal file
View File

@@ -0,0 +1,116 @@
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import gradio as gr
import os
from html_string import main_html,plain_html
from upload_file import *
from create_kb import *
from chat import get_model_response
def user(user_message, history):
print(user_message)
return {'text': '','files': user_message['files']}, history + [[user_message['text'], None]]
#####################################
###### gradio界面 #######
#####################################
def get_chat_block():
with gr.Blocks(theme=gr.themes.Base(),css=".gradio_container { background-color: #f0f0f0; }") as chat:
gr.HTML(plain_html)
with gr.Row():
with gr.Column(scale=10):
chatbot = gr.Chatbot(label="Chatbot",height=750,avatar_images=("images/user.jpeg","images/tongyi.png"))
with gr.Row():
#
input_message = gr.MultimodalTextbox(label="请输入",file_types=[".xlsx",".csv",".docx",".pdf",".txt"],scale=7)
clear_btn = gr.ClearButton(chatbot,input_message,scale=1)
# 模型与知识库参数
with gr.Column(scale=5):
knowledge_base =gr.Dropdown(choices=os.listdir(DB_PATH),label="加载知识库",interactive=True,scale=2)
with gr.Accordion(label="召回文本段",open=False):
chunk_text = gr.Textbox(label="召回文本段",interactive=False,scale=5,lines=10)
with gr.Accordion(label="模型设置",open=True):
model =gr.Dropdown(choices=['qwen-max','qwen-plus','qwen-turbo'],label="选择模型",interactive=True,value="qwen-max",scale=2)
temperature = gr.Slider(maximum=2,minimum=0,interactive=True,label="温度参数",step=0.01,value=0.85,scale=2)
max_tokens = gr.Slider(maximum=8000,minimum=0,interactive=True,label="最大回复长度",step=50,value=1024,scale=2)
history_round = gr.Slider(maximum=30,minimum=1,interactive=True,label="携带上下文轮数",step=1,value=3,scale=2)
with gr.Accordion(label="RAG参数设置",open=True):
chunk_cnt = gr.Slider(maximum=20,minimum=1,interactive=True,label="选择召回片段数",step=1,value=5,scale=2)
similarity_threshold = gr.Slider(maximum=1,minimum=0,interactive=True,label="相似度阈值",step=0.01,value=0.2,scale=2)
input_message.submit(fn=user,inputs=[input_message,chatbot],outputs=[input_message,chatbot],queue=False).then(
fn=get_model_response,inputs=[input_message,chatbot,model,temperature,max_tokens,history_round,knowledge_base,similarity_threshold,chunk_cnt],outputs=[chatbot,chunk_text]
)
chat.load(update_knowledge_base,[],knowledge_base)
chat.load(clear_tmp)
return chat
def get_upload_block():
with gr.Blocks(theme=gr.themes.Base()) as upload:
gr.HTML(plain_html)
with gr.Tab("非结构化数据"):
with gr.Accordion(label="新建类目",open=True):
with gr.Column(scale=2):
unstructured_file = gr.Files(file_types=["pdf","docx","txt"])
with gr.Row():
new_label = gr.Textbox(label="类目名称",placeholder="请输入类目名称",scale=5)
create_label_btn = gr.Button("新建类目",variant="primary",scale=1)
with gr.Accordion(label="管理类目",open=False):
with gr.Row():
data_label =gr.Dropdown(choices=os.listdir(UNSTRUCTURED_FILE_PATH),label="管理类目",interactive=True,scale=8,multiselect=True)
delete_label_btn = gr.Button("删除类目",variant="stop",scale=1)
with gr.Tab("结构化数据"):
with gr.Accordion(label="新建数据表",open=True):
with gr.Column(scale=2):
structured_file = gr.Files(file_types=["xlsx","csv"])
with gr.Row():
new_label_1 = gr.Textbox(label="数据表名称",placeholder="请输入数据表名称",scale=5)
create_label_btn_1 = gr.Button("新建数据表",variant="primary",scale=1)
with gr.Accordion(label="管理数据表",open=False):
with gr.Row():
data_label_1 =gr.Dropdown(choices=os.listdir(STRUCTURED_FILE_PATH),label="管理数据表",interactive=True,scale=8,multiselect=True)
delete_data_table_btn = gr.Button("删除数据表",variant="stop",scale=1)
delete_label_btn.click(delete_label,inputs=[data_label]).then(fn=update_label,outputs=[data_label])
create_label_btn.click(fn=upload_unstructured_file,inputs=[unstructured_file,new_label]).then(fn=update_label,outputs=[data_label])
delete_data_table_btn.click(delete_data_table,inputs=[data_label_1]).then(fn=update_datatable,outputs=[data_label_1])
create_label_btn_1.click(fn=upload_structured_file,inputs=[structured_file,new_label_1]).then(fn=update_datatable,outputs=[data_label_1])
upload.load(update_label,[],data_label)
upload.load(update_datatable,[],data_label_1)
return upload
def get_knowledge_base_block():
with gr.Blocks(theme=gr.themes.Base()) as knowledge:
gr.HTML(plain_html)
# 非结构化数据知识库
with gr.Tab("非结构化数据"):
with gr.Row():
data_label_2 =gr.Dropdown(choices=os.listdir(UNSTRUCTURED_FILE_PATH),label="选择类目",interactive=True,scale=2,multiselect=True)
knowledge_base_name = gr.Textbox(label="知识库名称",placeholder="请输入知识库名称",scale=2)
create_knowledge_base_btn = gr.Button("确认创建知识库",variant="primary",scale=1)
# 结构化数据知识库
with gr.Tab("结构化数据"):
with gr.Row():
data_label_3 =gr.Dropdown(choices=os.listdir(STRUCTURED_FILE_PATH),label="选择数据表",interactive=True,scale=2,multiselect=True)
knowledge_base_name_1 = gr.Textbox(label="知识库名称",placeholder="请输入知识库名称",scale=2)
create_knowledge_base_btn_1 = gr.Button("确认创建知识库",variant="primary",scale=1)
with gr.Row():
knowledge_base =gr.Dropdown(choices=os.listdir(DB_PATH),label="管理知识库",interactive=True,scale=4)
delete_db_btn = gr.Button("删除知识库",variant="stop",scale=1)
create_knowledge_base_btn.click(fn=create_unstructured_db,inputs=[knowledge_base_name,data_label_2]).then(update_knowledge_base,outputs=[knowledge_base])
delete_db_btn.click(delete_db,inputs=[knowledge_base]).then(update_knowledge_base,outputs=[knowledge_base])
create_knowledge_base_btn_1.click(fn=create_structured_db,inputs=[knowledge_base_name_1,data_label_3]).then(update_knowledge_base,outputs=[knowledge_base])
knowledge.load(update_knowledge_base,[],knowledge_base)
knowledge.load(update_label,[],data_label_2)
knowledge.load(update_datatable,[],data_label_3)
return knowledge
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def read_main():
html_content = main_html
return HTMLResponse(content=html_content)
app = gr.mount_gradio_app(app, get_chat_block(), path="/chat")
app = gr.mount_gradio_app(app, get_upload_block(), path="/upload_data")
app = gr.mount_gradio_app(app, get_knowledge_base_block(), path="/create_knowledge_base")

View File

@@ -0,0 +1,26 @@
gradio==4.32.0
faiss-cpu==1.8.0.post1
dashscope==1.20.4
openai==1.55.3
httpx==0.27.0
llama-index-vector-stores-faiss==0.1.2
llama-index-embeddings-dashscope==0.1.4
llama-index-readers-file==0.1.33
matplotlib==3.9.3
docx2txt==0.8
openpyxl==3.1.5
llama-index-core==0.10.67
uvicorn==0.30.6
fastapi==0.112.0
llama-index-postprocessor-dashscope-rerank-custom==0.1.0
simplejson==3.19.3
pydantic==2.10.6
# modelscope==1.18.0
# langchain_community==0.2.16
# transformers==4.44.2
# llama_index.embeddings.huggingface==0.2.3
# llama-index-embeddings-langchain==0.1.2
# datasets==2.21.0
# oss2==2.19.0
# sortedcontainers==2.4.0
# addict==2.4.0s

107
local_rag/upload_file.py Normal file
View File

@@ -0,0 +1,107 @@
#####################################
####### 上传文件 #######
#####################################
import gradio as gr
import os
import shutil
import pandas as pd
STRUCTURED_FILE_PATH = "File/Structured"
UNSTRUCTURED_FILE_PATH = "File/Unstructured"
# 刷新非结构化类目
def refresh_label():
return os.listdir(UNSTRUCTURED_FILE_PATH)
# 刷新结构化数据表
def refresh_data_table():
return os.listdir(STRUCTURED_FILE_PATH)
# 上传非结构化数据
def upload_unstructured_file(files,label_name):
if files is None:
gr.Info("请上传文件")
elif len(label_name) == 0:
gr.Info("请输入类目名称")
# 判断类目是否存在
elif label_name in os.listdir(UNSTRUCTURED_FILE_PATH):
gr.Info(f"{label_name}类目已存在")
else:
try:
if not os.path.exists(os.path.join(UNSTRUCTURED_FILE_PATH,label_name)):
os.mkdir(os.path.join(UNSTRUCTURED_FILE_PATH,label_name))
for file in files:
print(file)
file_path = file.name
file_name = os.path.basename(file_path)
destination_file_path = os.path.join(UNSTRUCTURED_FILE_PATH,label_name,file_name)
shutil.move(file_path,destination_file_path)
gr.Info(f"文件已上传至{label_name}类目中,请前往创建知识库")
except:
gr.Info(f"请勿重复上传")
# 上传结构化数据
def upload_structured_file(files,label_name):
if files is None:
gr.Info("请上传文件")
elif len(label_name) == 0:
gr.Info("请输入数据表名称")
# 判断数据表是否存在
elif label_name in os.listdir(STRUCTURED_FILE_PATH):
gr.Info(f"{label_name}数据表已存在")
else:
try:
if not os.path.exists(os.path.join(STRUCTURED_FILE_PATH,label_name)):
os.mkdir(os.path.join(STRUCTURED_FILE_PATH,label_name))
for file in files:
file_path = file.name
file_name = os.path.basename(file_path)
destination_file_path = os.path.join(STRUCTURED_FILE_PATH,label_name,file_name)
shutil.move(file_path,destination_file_path)
if os.path.splitext(destination_file_path)[1] == ".xlsx":
df = pd.read_excel(destination_file_path)
elif os.path.splitext(destination_file_path)[1] == ".csv":
df = pd.read_csv(destination_file_path)
txt_file_name = os.path.splitext(file_name)[0]+'.txt'
columns = df.columns
with open(os.path.join(STRUCTURED_FILE_PATH,label_name,txt_file_name),"w") as file:
for idx,row in df.iterrows():
file.write("")
info = []
for col in columns:
info.append(f"{col}:{row[col]}")
infos = ",".join(info)
file.write(infos)
if idx != len(df)-1:
file.write("\n")
else:
file.write("")
os.remove(destination_file_path)
gr.Info(f"文件已上传至{label_name}数据表中,请前往创建知识库")
except:
gr.Info(f"请勿重复上传")
# 实时更新结构化数据表
def update_datatable():
return gr.update(choices=os.listdir(STRUCTURED_FILE_PATH))
# 实时更新非结构化类目
def update_label():
return gr.update(choices=os.listdir(UNSTRUCTURED_FILE_PATH))
# 删除类目
def delete_label(label_name):
if label_name is not None:
for label in label_name:
folder_path = os.path.join(UNSTRUCTURED_FILE_PATH,label)
if os.path.exists(folder_path):
shutil.rmtree(folder_path)
gr.Info(f"{label}类目已删除")
# 删除数据表
def delete_data_table(table_name):
if table_name is not None:
for table in table_name:
folder_path = os.path.join(STRUCTURED_FILE_PATH,table)
if os.path.exists(folder_path):
shutil.rmtree(folder_path)
gr.Info(f"{table}数据表已删除")

12
requirements.txt Normal file
View File

@@ -0,0 +1,12 @@
openai
dashscope
langchain
langchain-deepseek
langchain-community
llama-index
llama-index-core
llama-index-llms-dashscope
llama-index-indices-managed-dashscope
qwen-agent

38
setup.py Normal file
View File

@@ -0,0 +1,38 @@
from setuptools import setup, find_packages
with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()
with open("requirements.txt", "r", encoding="utf-8") as fh:
requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
setup(
name="knightutils",
version="0.1.0",
author="Unknown",
author_email="unknown@example.com",
description="A utility package for sharing code",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/yourusername/knightutils",
packages=find_packages(),
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],
python_requires=">=3.7",
install_requires=requirements,
extras_require={
"dev": [
"pytest>=6.0",
"pytest-cov>=2.0",
],
},
)

View File

@@ -0,0 +1,23 @@
import os
from openai import OpenAI
client = OpenAI(
# 若没有配置环境变量请用阿里云百炼API Key将下行替换为api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"), # 如何获取API Keyhttps://help.aliyun.com/zh/model-studio/developer-reference/get-api-key
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
completion = client.chat.completions.create(
model="deepseek-r1", # 此处以 deepseek-r1 为例,可按需更换模型名称。
messages=[
{'role': 'user', 'content': '9.9和9.11谁大'}
]
)
# 通过reasoning_content字段打印思考过程
print("思考过程:")
print(completion.choices[0].message.reasoning_content)
# 通过content字段打印最终答案
print("最终答案:")
print(completion.choices[0].message.content)

21
test/compatible/qwen.py Normal file
View File

@@ -0,0 +1,21 @@
import os
from openai import OpenAI
client = OpenAI(
# 若没有配置环境变量请用百炼API Key将下行替换为api_key="sk-xxx",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
completion = client.chat.completions.create(
# 模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
model="qwen-plus",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你是谁?"},
],
# Qwen3模型通过enable_thinking参数控制思考过程开源版默认True商业版默认False
# 使用Qwen3开源版模型时若未启用流式输出请将下行取消注释否则会报错
# extra_body={"enable_thinking": False},
)
print(completion.model_dump_json())

View File

@@ -0,0 +1,20 @@
import os
import dashscope
messages = [
{'role': 'user', 'content': '你是谁?'}
]
response = dashscope.Generation.call(
# 若没有配置环境变量请用阿里云百炼API Key将下行替换为api_key="sk-xxx",
api_key=os.getenv('DASHSCOPE_API_KEY'),
model="deepseek-r1", # 此处以 deepseek-r1 为例,可按需更换模型名称。
messages=messages,
# result_format参数不可以设置为"text"。
result_format='message'
)
print("=" * 20 + "思考过程" + "=" * 20)
print(response.output.choices[0].message.reasoning_content)
print("=" * 20 + "最终答案" + "=" * 20)
print(response.output.choices[0].message.content)

15
test/dashscope/qwen.py Normal file
View File

@@ -0,0 +1,15 @@
import os
import dashscope
messages = [
{'role': 'system', 'content': 'You are a helpful assistant.'},
{'role': 'user', 'content': '你是谁?'}
]
response = dashscope.Generation.call(
# 若没有配置环境变量请用百炼API Key将下行替换为api_key="sk-xxx",
api_key=os.getenv('DASHSCOPE_API_KEY'),
model="qwen-plus", # 此处以qwen-plus为例可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
messages=messages,
result_format='message'
)
print(response)

View File

@@ -0,0 +1,15 @@
from langchain_openai import ChatOpenAI
from langchain_deepseek import ChatDeepSeek
import os
chatLLM = ChatDeepSeek(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="deepseek-chat", # 此处以qwen-plus为例您可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
# other params...
)
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你是谁?"}]
response = chatLLM.invoke(messages)
print(response.model_dump_json())

View File

@@ -0,0 +1,14 @@
from langchain_openai import ChatOpenAI
import os
chatLLM = ChatOpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-plus", # 此处以qwen-plus为例您可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
# other params...
)
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你是谁?"}]
response = chatLLM.invoke(messages)
print(response.model_dump_json())

View File

@@ -0,0 +1,11 @@
from langchain_community.chat_models.tongyi import ChatTongyi
from langchain_core.messages import HumanMessage
chatLLM = ChatTongyi(
model="qwen-max", # 此处以qwen-max为例您可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
streaming=True,
# other params...
)
res = chatLLM.stream([HumanMessage(content="hi")], streaming=True)
for r in res:
print("chat resp:", r.content)

View File

@@ -0,0 +1,15 @@
import getpass
import os
if not os.environ.get("DEEPSEEK_API_KEY"):
os.environ["DEEPSEEK_API_KEY"] = os.environ['DASHSCOPE_API_KEY']
from langchain.chat_models import init_chat_model
model = init_chat_model("deepseek-chat", model_provider="deepseek")
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你是谁?"}]
response = model.invoke(messages)
print(response.model_dump_json())

15
test/langchain/qwen.py Normal file
View File

@@ -0,0 +1,15 @@
import getpass
import os
if not os.environ.get("DEEPSEEK_API_KEY"):
os.environ["DEEPSEEK_API_KEY"] = os.environ['DASHSCOPE_API_KEY']
from langchain.chat_models import init_chat_model
model = init_chat_model("qwen-max", model_provider="deepseek")
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "你是谁?"}]
response = model.invoke(messages)
print(response.model_dump_json())

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,144 @@
# Step 0: Define tools and model
from langchain_core.tools import tool
from langchain_community.chat_models.tongyi import ChatTongyi
llm = ChatTongyi(
model="qwen-max", # 此处以qwen-max为例您可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
streaming=True,
# other params...
)
# Define tools
@tool
def multiply(a: int, b: int) -> int:
"""Multiply a and b.
Args:
a: first int
b: second int
"""
return a * b
@tool
def add(a: int, b: int) -> int:
"""Adds a and b.
Args:
a: first int
b: second int
"""
return a + b
@tool
def divide(a: int, b: int) -> float:
"""Divide a and b.
Args:
a: first int
b: second int
"""
return a / b
# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
llm_with_tools = llm.bind_tools(tools)
# Step 1: Define state
from langchain_core.messages import AnyMessage
from typing_extensions import TypedDict, Annotated
import operator
class MessagesState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add]
llm_calls: int
# Step 2: Define model node
from langchain_core.messages import SystemMessage
def llm_call(state: dict):
"""LLM decides whether to call a tool or not"""
return {
"messages": [
llm_with_tools.invoke(
[
SystemMessage(
content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
)
]
+ state["messages"]
)
],
"llm_calls": state.get('llm_calls', 0) + 1
}
# Step 3: Define tool node
from langchain_core.messages import ToolMessage
def tool_node(state: dict):
"""Performs the tool call"""
result = []
for tool_call in state["messages"][-1].tool_calls:
tool = tools_by_name[tool_call["name"]]
observation = tool.invoke(tool_call["args"])
result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
return {"messages": result}
# Step 4: Define logic to determine whether to end
from typing import Literal
from langgraph.graph import StateGraph, START, END
# Conditional edge function to route to the tool node or end based upon whether the LLM made a tool call
def should_continue(state: MessagesState) -> Literal["tool_node", END]:
"""Decide if we should continue the loop or stop based upon whether the LLM made a tool call"""
messages = state["messages"]
last_message = messages[-1]
# If the LLM makes a tool call, then perform an action
if last_message.tool_calls:
return "tool_node"
# Otherwise, we stop (reply to the user)
return END
# Step 5: Build agent
# Build workflow
agent_builder = StateGraph(MessagesState)
# Add nodes
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)
# Add edges to connect nodes
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
"llm_call",
should_continue,
["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")
# Compile the agent
agent = agent_builder.compile()
from IPython.display import Image, display
# Show the agent
display(Image(agent.get_graph(xray=True).draw_mermaid_png()))
# Invoke
# from langchain_core.messages import HumanMessage
# messages = [HumanMessage(content="Add 3 and 4.")]
# messages = agent.invoke({"messages": messages})
# for m in messages["messages"]:
# m.pretty_print()

View File

@@ -0,0 +1,205 @@
{
"cells": [
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"ExecuteTime": {
"end_time": "2025-09-12T15:52:56.909385Z",
"start_time": "2025-09-12T15:52:56.417088Z"
}
},
"source": [
"import os\n",
"\n",
"os.environ['DASHSCOPE_API_KEY'] = 'sk-e2a05bbcfac84e53b73f98acef15a009'\n",
"\n",
"# Step 0: Define tools and model\n",
"\n",
"from langchain_core.tools import tool\n",
"from langchain_community.chat_models.tongyi import ChatTongyi\n",
"\n",
"llm = ChatTongyi(\n",
" model=\"qwen-max\", # 此处以qwen-max为例您可按需更换模型名称。模型列表https://help.aliyun.com/zh/model-studio/getting-started/models\n",
" streaming=True,\n",
" # other params...\n",
")"
],
"outputs": [],
"execution_count": 1
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-09-12T15:54:08.425580Z",
"start_time": "2025-09-12T15:54:08.374623Z"
}
},
"cell_type": "code",
"source": [
"\n",
"\n",
"# Define tools\n",
"@tool\n",
"def multiply(a: int, b: int) -> int:\n",
" \"\"\"Multiply a and b.\n",
"\n",
" Args:\n",
" a: first int\n",
" b: second int\n",
" \"\"\"\n",
" return a * b\n",
"\n",
"\n",
"@tool\n",
"def add(a: int, b: int) -> int:\n",
" \"\"\"Adds a and b.\n",
"\n",
" Args:\n",
" a: first int\n",
" b: second int\n",
" \"\"\"\n",
" return a + b\n",
"\n",
"\n",
"@tool\n",
"def divide(a: int, b: int) -> float:\n",
" \"\"\"Divide a and b.\n",
"\n",
" Args:\n",
" a: first int\n",
" b: second int\n",
" \"\"\"\n",
" return a / b\n",
"\n",
"\n",
"# Augment the LLM with tools\n",
"tools = [add, multiply, divide]\n",
"tools_by_name = {tool.name: tool for tool in tools}\n",
"llm_with_tools = llm.bind_tools(tools)\n",
"\n",
"from langgraph.graph import add_messages\n",
"from langchain_core.messages import (\n",
" SystemMessage,\n",
" HumanMessage,\n",
" BaseMessage,\n",
" ToolCall,\n",
")\n",
"from langgraph.func import entrypoint, task\n",
"\n",
"# Step 1: define model node\n",
"@task\n",
"def call_llm(messages: list[BaseMessage]):\n",
" \"\"\"LLM decides whether to call a tool or not\"\"\"\n",
" return llm_with_tools.invoke(\n",
" [\n",
" SystemMessage(\n",
" content=\"You are a helpful assistant tasked with performing arithmetic on a set of inputs.\"\n",
" )\n",
" ]\n",
" + messages\n",
" )\n",
"\n",
"\n",
"# Step 2: define tool node\n",
"@task\n",
"def call_tool(tool_call: ToolCall):\n",
" \"\"\"Performs the tool call\"\"\"\n",
" tool = tools_by_name[tool_call[\"name\"]]\n",
" return tool.invoke(tool_call)\n",
"\n",
"\n",
"# Step 3: define agent\n",
"@entrypoint()\n",
"def agent(messages: list[BaseMessage]):\n",
" llm_response = call_llm(messages).result()\n",
"\n",
" while True:\n",
" if not llm_response.tool_calls:\n",
" break\n",
"\n",
" # Execute tools\n",
" tool_result_futures = [\n",
" call_tool(tool_call) for tool_call in llm_response.tool_calls\n",
" ]\n",
" tool_results = [fut.result() for fut in tool_result_futures]\n",
" messages = add_messages(messages, [llm_response, *tool_results])\n",
" llm_response = call_llm(messages).result()\n",
"\n",
" messages = add_messages(messages, llm_response)\n",
" return messages"
],
"id": "8a77a9b24ee9616d",
"outputs": [],
"execution_count": 2
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-09-12T15:54:11.693756Z",
"start_time": "2025-09-12T15:54:10.101700Z"
}
},
"cell_type": "code",
"source": [
"\n",
"# Invoke\n",
"messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
"for chunk in agent.stream(messages, stream_mode=\"updates\"):\n",
" print(chunk)\n",
" print(\"\\n\")"
],
"id": "7c4b06da8200b106",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'call_llm': AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_ef8c897dd4f84afbbf0927', 'type': 'function', 'function': {'name': 'add', 'arguments': '{\"a\": 3, \"b\": 4}'}}]}, response_metadata={'model_name': 'qwen-max', 'finish_reason': 'tool_calls', 'request_id': '6d8c6555-1a67-4cc9-a93f-57e94bc20842', 'token_usage': {'input_tokens': 354, 'output_tokens': 22, 'total_tokens': 376, 'prompt_tokens_details': {'cached_tokens': 0}}}, id='lc_run--afcea3de-940e-45c6-ba96-bbd7e41fa115-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_ef8c897dd4f84afbbf0927', 'type': 'tool_call'}], chunk_position=None)}\n",
"\n",
"\n",
"{'call_tool': ToolMessage(content='7', name='add', id='aeaf3d29-254b-48ab-a933-814e9ea72394', tool_call_id='call_ef8c897dd4f84afbbf0927')}\n",
"\n",
"\n",
"{'call_llm': AIMessage(content='The sum of 3 and 4 is 7.', additional_kwargs={}, response_metadata={'model_name': 'qwen-max', 'finish_reason': 'stop', 'request_id': '310102ab-48dc-4e80-bc57-ca8814239a65', 'token_usage': {'input_tokens': 386, 'output_tokens': 13, 'total_tokens': 399, 'prompt_tokens_details': {'cached_tokens': 0}}}, id='lc_run--b3dffae8-42c2-492e-a1f4-e659eba6a879-0', chunk_position=None)}\n",
"\n",
"\n",
"{'agent': [HumanMessage(content='Add 3 and 4.', additional_kwargs={}, response_metadata={}, id='40fc3758-a8ab-4302-aff9-8dfbdec16fa0'), AIMessage(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_ef8c897dd4f84afbbf0927', 'type': 'function', 'function': {'name': 'add', 'arguments': '{\"a\": 3, \"b\": 4}'}}]}, response_metadata={'model_name': 'qwen-max', 'finish_reason': 'tool_calls', 'request_id': '6d8c6555-1a67-4cc9-a93f-57e94bc20842', 'token_usage': {'input_tokens': 354, 'output_tokens': 22, 'total_tokens': 376, 'prompt_tokens_details': {'cached_tokens': 0}}}, id='lc_run--afcea3de-940e-45c6-ba96-bbd7e41fa115-0', tool_calls=[{'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'call_ef8c897dd4f84afbbf0927', 'type': 'tool_call'}], chunk_position=None), ToolMessage(content='7', name='add', id='aeaf3d29-254b-48ab-a933-814e9ea72394', tool_call_id='call_ef8c897dd4f84afbbf0927'), AIMessage(content='The sum of 3 and 4 is 7.', additional_kwargs={}, response_metadata={'model_name': 'qwen-max', 'finish_reason': 'stop', 'request_id': '310102ab-48dc-4e80-bc57-ca8814239a65', 'token_usage': {'input_tokens': 386, 'output_tokens': 13, 'total_tokens': 399, 'prompt_tokens_details': {'cached_tokens': 0}}}, id='lc_run--b3dffae8-42c2-492e-a1f4-e659eba6a879-0', chunk_position=None)]}\n",
"\n",
"\n"
]
}
],
"execution_count": 3
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "7e55492ae0289f06"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,25 @@
import os
from llama_index.readers.dashscope.base import DashScopeParse
from llama_index.readers.dashscope.utils import ResultType
# 设置业务空间 ID 将决定文档解析结果在”创建知识库“步骤中上传到哪个业务空间
os.environ['DASHSCOPE_WORKSPACE_ID'] = "<Your Workspace id, Default workspace is empty.>"
# 第一种方式:使用文档解析器解析一个或多个文件
file = [
# 需要解析的文件支持pdf,doc,docx
]
# 解析文件
parse = DashScopeParse(result_type=ResultType.DASHSCOPE_DOCMIND)
documents = parse.load_data(file_path=file)
# 第二种方式:使用文档解析器解析一个文件夹内指定类型的文件
from llama_index.core import SimpleDirectoryReader
parse = DashScopeParse(result_type=ResultType.DASHSCOPE_DOCMIND)
# 定义不同文档类型的解析器
file_extractor = {".pdf": parse, '.doc': parse, '.docx': parse}
# 读取文件夹,提取和解析文件信息
documents = SimpleDirectoryReader(
"your_folder", file_extractor=file_extractor
).load_data(num_workers=1)

View File

@@ -0,0 +1,7 @@
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("Some question about the data should go here")
print(response)

2
test/llamaindex/env Normal file
View File

@@ -0,0 +1,2 @@
# MacOS/Linux
export OPENAI_API_KEY=sk-e2a05bbcfac84e53b73f98acef15a009

View File

@@ -0,0 +1,51 @@
You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.
## Tools
You have access to a wide variety of tools. You are responsible for using the tools in any sequence you deem appropriate to complete the task at hand.
This may require breaking the task into subtasks and using different tools to complete each subtask.
You have access to the following tools:
> Tool Name: multiply
Tool Description: multiply(a: float, b: float) -> float
Useful for multiplying two numbers.
Tool Args: {\"type\": \"object\", \"properties\": {\"a\": {\"title\": \"A\", \"type\": \"number\"}, \"b\": {\"title\": \"B\", \"type\": \"number\"}}, \"required\": [\"a\", \"b\"]}
## Output Format
Please answer in the same language as the question and use the following format:
```
Thought: The current language of the user is: (user's language). I need to use a tool to help me answer the question.
Action: tool name (one of multiply) if using a tool.
Action Input: the input to the tool, in a JSON format representing the kwargs (e.g. {\"input\": \"hello world\", \"num_beams\": 5})
```
Please ALWAYS start with a Thought.
NEVER surround your response with markdown code markers. You may use code markers within your response if you need to.
Please use a valid JSON format for the Action Input. Do NOT do this {'input': 'hello world', 'num_beams': 5}.
If this format is used, the user will respond in the following format:
```
Observation: tool response
```
You should keep repeating the above format till you have enough information to answer the question without using any more tools. At that point, you MUST respond in the one of the following two formats:
```
Thought: I can answer without using any more tools. I'll use the user's language to answer
Answer: [your answer here (In the same language as the user's question)]
```
```
Thought: I cannot answer the question with the provided tools.
Answer: [your answer here (In the same language as the user's question)]
```
## Current Conversation
Below is the current conversation consisting of interleaving human and assistant messages.

View File

@@ -0,0 +1,30 @@
import asyncio
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.dashscope import DashScope
# Define a simple calculator tool
def multiply(a: float, b: float) -> float:
"""Useful for multiplying two numbers."""
return a * b
# Create an agent workflow with our calculator tool
llm = DashScope(model_name="qwen-max")
agent = ReActAgent.from_tools(
tools=[FunctionTool.from_defaults(fn=multiply)],
llm=llm,
verbose=True,
)
async def main():
# Run the agent
response = await agent.achat("What is 1234 * 4567?")
print(str(response))
# Run the agent
if __name__ == "__main__":
asyncio.run(main())

7
test/llamaindex/test1.py Normal file
View File

@@ -0,0 +1,7 @@
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("Some question about the data should go here")
print(response)

View File

@@ -0,0 +1,117 @@
{
"cells": [
{
"cell_type": "code",
"id": "2eeef59eecfab41a",
"metadata": {
"ExecuteTime": {
"end_time": "2025-08-27T16:02:52.719750Z",
"start_time": "2025-08-27T16:02:51.725308Z"
}
},
"source": [
"import os\n",
"\n",
"from llama_index.llms.dashscope import DashScope\n",
"from llama_index.llms.openai import OpenAI\n",
"from knightutils.utils.set_proxy import set_proxy_with_os\n",
"\n",
"set_proxy_with_os()\n",
"\n",
"os.environ[\"DASHSCOPE_API_KEY\"] = \"sk-e2a05bbcfac84e53b73f98acef15a009\"\n",
"# llm = DashScope(model_name=\"qwen-max\", verify=False) # 设置检索引擎生成回答时调用的大模型。\n",
"llm = DashScope(model_name=\"qwen-max\") # 设置检索引擎生成回答时调用的大模型。"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"已通过环境变量设置代理\n"
]
}
],
"execution_count": 1
},
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2025-08-27T16:02:58.073124Z",
"start_time": "2025-08-27T16:02:57.170496Z"
}
},
"source": [
"response = llm.complete(\"William Shakespeare is \")\n",
"print(response)"
],
"outputs": [
{
"ename": "SSLError",
"evalue": "HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/aigc/text-generation/generation (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)')))",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mSSLError\u001B[0m Traceback (most recent call last)",
"\u001B[0;31mSSLError\u001B[0m: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)",
"\nThe above exception was the direct cause of the following exception:\n",
"\u001B[0;31mMaxRetryError\u001B[0m Traceback (most recent call last)",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/requests/adapters.py:644\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[1;32m 643\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 644\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43murlopen\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 645\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 646\u001B[0m \u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 647\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 648\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 649\u001B[0m \u001B[43m \u001B[49m\u001B[43mredirect\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 650\u001B[0m \u001B[43m \u001B[49m\u001B[43massert_same_host\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 651\u001B[0m \u001B[43m \u001B[49m\u001B[43mpreload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 652\u001B[0m \u001B[43m \u001B[49m\u001B[43mdecode_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 653\u001B[0m \u001B[43m \u001B[49m\u001B[43mretries\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmax_retries\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 654\u001B[0m \u001B[43m \u001B[49m\u001B[43mtimeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtimeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 655\u001B[0m \u001B[43m \u001B[49m\u001B[43mchunked\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchunked\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 656\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 658\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (ProtocolError, \u001B[38;5;167;01mOSError\u001B[39;00m) \u001B[38;5;28;01mas\u001B[39;00m err:\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/urllib3/connectionpool.py:841\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001B[0m\n\u001B[1;32m 839\u001B[0m new_e \u001B[38;5;241m=\u001B[39m ProtocolError(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mConnection aborted.\u001B[39m\u001B[38;5;124m\"\u001B[39m, new_e)\n\u001B[0;32m--> 841\u001B[0m retries \u001B[38;5;241m=\u001B[39m \u001B[43mretries\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mincrement\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 842\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43merror\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mnew_e\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_pool\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_stacktrace\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msys\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexc_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m2\u001B[39;49m\u001B[43m]\u001B[49m\n\u001B[1;32m 843\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 844\u001B[0m retries\u001B[38;5;241m.\u001B[39msleep()\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/urllib3/util/retry.py:519\u001B[0m, in \u001B[0;36mRetry.increment\u001B[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001B[0m\n\u001B[1;32m 518\u001B[0m reason \u001B[38;5;241m=\u001B[39m error \u001B[38;5;129;01mor\u001B[39;00m ResponseError(cause)\n\u001B[0;32m--> 519\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m MaxRetryError(_pool, url, reason) \u001B[38;5;28;01mfrom\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21;01mreason\u001B[39;00m \u001B[38;5;66;03m# type: ignore[arg-type]\u001B[39;00m\n\u001B[1;32m 521\u001B[0m log\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mIncremented Retry for (url=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m): \u001B[39m\u001B[38;5;132;01m%r\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, url, new_retry)\n",
"\u001B[0;31mMaxRetryError\u001B[0m: HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/aigc/text-generation/generation (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)')))",
"\nDuring handling of the above exception, another exception occurred:\n",
"\u001B[0;31mSSLError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[2], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mllm\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcomplete\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mWilliam Shakespeare is \u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28mprint\u001B[39m(response)\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/llama_index/core/instrumentation/dispatcher.py:260\u001B[0m, in \u001B[0;36mDispatcher.span.<locals>.wrapper\u001B[0;34m(func, instance, args, kwargs)\u001B[0m\n\u001B[1;32m 252\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mspan_enter(\n\u001B[1;32m 253\u001B[0m id_\u001B[38;5;241m=\u001B[39mid_,\n\u001B[1;32m 254\u001B[0m bound_args\u001B[38;5;241m=\u001B[39mbound_args,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 257\u001B[0m tags\u001B[38;5;241m=\u001B[39mtags,\n\u001B[1;32m 258\u001B[0m )\n\u001B[1;32m 259\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 260\u001B[0m result \u001B[38;5;241m=\u001B[39m \u001B[43mfunc\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43margs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 261\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mBaseException\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m 262\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mevent(SpanDropEvent(span_id\u001B[38;5;241m=\u001B[39mid_, err_str\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mstr\u001B[39m(e)))\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/llama_index/core/llms/callbacks.py:429\u001B[0m, in \u001B[0;36mllm_completion_callback.<locals>.wrap.<locals>.wrapped_llm_predict\u001B[0;34m(_self, *args, **kwargs)\u001B[0m\n\u001B[1;32m 420\u001B[0m event_id \u001B[38;5;241m=\u001B[39m callback_manager\u001B[38;5;241m.\u001B[39mon_event_start(\n\u001B[1;32m 421\u001B[0m CBEventType\u001B[38;5;241m.\u001B[39mLLM,\n\u001B[1;32m 422\u001B[0m payload\u001B[38;5;241m=\u001B[39m{\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 426\u001B[0m },\n\u001B[1;32m 427\u001B[0m )\n\u001B[1;32m 428\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 429\u001B[0m f_return_val \u001B[38;5;241m=\u001B[39m \u001B[43mf\u001B[49m\u001B[43m(\u001B[49m\u001B[43m_self\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43margs\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 430\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mBaseException\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m 431\u001B[0m callback_manager\u001B[38;5;241m.\u001B[39mon_event_end(\n\u001B[1;32m 432\u001B[0m CBEventType\u001B[38;5;241m.\u001B[39mLLM,\n\u001B[1;32m 433\u001B[0m payload\u001B[38;5;241m=\u001B[39m{EventPayload\u001B[38;5;241m.\u001B[39mEXCEPTION: e},\n\u001B[1;32m 434\u001B[0m event_id\u001B[38;5;241m=\u001B[39mevent_id,\n\u001B[1;32m 435\u001B[0m )\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/llama_index/llms/dashscope/base.py:228\u001B[0m, in \u001B[0;36mDashScope.complete\u001B[0;34m(self, prompt, **kwargs)\u001B[0m\n\u001B[1;32m 226\u001B[0m parameters\u001B[38;5;241m.\u001B[39mpop(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstream\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mNone\u001B[39;00m)\n\u001B[1;32m 227\u001B[0m messages \u001B[38;5;241m=\u001B[39m chat_message_to_dashscope_messages([message])\n\u001B[0;32m--> 228\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mcall_with_messages\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 229\u001B[0m \u001B[43m \u001B[49m\u001B[43mmodel\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmodel_name\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 230\u001B[0m \u001B[43m \u001B[49m\u001B[43mmessages\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mmessages\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 231\u001B[0m \u001B[43m \u001B[49m\u001B[43mapi_key\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_key\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 232\u001B[0m \u001B[43m \u001B[49m\u001B[43mparameters\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparameters\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 233\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 234\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m dashscope_response_to_completion_response(response)\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/llama_index/llms/dashscope/base.py:83\u001B[0m, in \u001B[0;36mcall_with_messages\u001B[0;34m(model, messages, parameters, api_key, **kwargs)\u001B[0m\n\u001B[1;32m 78\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n\u001B[1;32m 79\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\n\u001B[1;32m 80\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mDashScope is not installed. Please install it with \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m 81\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m`pip install dashscope`.\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m 82\u001B[0m )\n\u001B[0;32m---> 83\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mGeneration\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 84\u001B[0m \u001B[43m \u001B[49m\u001B[43mmodel\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mmodel\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmessages\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mmessages\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mapi_key\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mapi_key\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mparameters\u001B[49m\n\u001B[1;32m 85\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/dashscope/aigc/generation.py:138\u001B[0m, in \u001B[0;36mGeneration.call\u001B[0;34m(cls, model, prompt, history, api_key, messages, plugins, workspace, **kwargs)\u001B[0m\n\u001B[1;32m 135\u001B[0m kwargs[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mheaders\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m headers\n\u001B[1;32m 136\u001B[0m \u001B[38;5;28minput\u001B[39m, parameters \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mcls\u001B[39m\u001B[38;5;241m.\u001B[39m_build_input_parameters(\n\u001B[1;32m 137\u001B[0m model, prompt, history, messages, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m--> 138\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43msuper\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmodel\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mmodel\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 139\u001B[0m \u001B[43m \u001B[49m\u001B[43mtask_group\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtask_group\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 140\u001B[0m \u001B[43m \u001B[49m\u001B[43mtask\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mGeneration\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mtask\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 141\u001B[0m \u001B[43m \u001B[49m\u001B[43mfunction\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mfunction\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 142\u001B[0m \u001B[43m \u001B[49m\u001B[43mapi_key\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mapi_key\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 143\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43minput\u001B[39;49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43minput\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 144\u001B[0m \u001B[43m \u001B[49m\u001B[43mworkspace\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mworkspace\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 145\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mparameters\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 146\u001B[0m is_stream \u001B[38;5;241m=\u001B[39m kwargs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mstream\u001B[39m\u001B[38;5;124m'\u001B[39m, \u001B[38;5;28;01mFalse\u001B[39;00m)\n\u001B[1;32m 147\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m is_stream:\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/dashscope/client/base_api.py:146\u001B[0m, in \u001B[0;36mBaseApi.call\u001B[0;34m(cls, model, input, task_group, task, function, api_key, workspace, **kwargs)\u001B[0m\n\u001B[1;32m 138\u001B[0m request \u001B[38;5;241m=\u001B[39m _build_api_request(model\u001B[38;5;241m=\u001B[39mmodel,\n\u001B[1;32m 139\u001B[0m \u001B[38;5;28minput\u001B[39m\u001B[38;5;241m=\u001B[39m\u001B[38;5;28minput\u001B[39m,\n\u001B[1;32m 140\u001B[0m task_group\u001B[38;5;241m=\u001B[39mtask_group,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 143\u001B[0m api_key\u001B[38;5;241m=\u001B[39mapi_key,\n\u001B[1;32m 144\u001B[0m \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[1;32m 145\u001B[0m \u001B[38;5;66;03m# call request service.\u001B[39;00m\n\u001B[0;32m--> 146\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/dashscope/api_entities/http_request.py:84\u001B[0m, in \u001B[0;36mHttpRequest.call\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 82\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m (item \u001B[38;5;28;01mfor\u001B[39;00m item \u001B[38;5;129;01min\u001B[39;00m response)\n\u001B[1;32m 83\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m---> 84\u001B[0m output \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mnext\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43mresponse\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 85\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m 86\u001B[0m \u001B[38;5;28mnext\u001B[39m(response)\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/dashscope/api_entities/http_request.py:303\u001B[0m, in \u001B[0;36mHttpRequest._handle_request\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 301\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mBaseException\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m 302\u001B[0m logger\u001B[38;5;241m.\u001B[39merror(e)\n\u001B[0;32m--> 303\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m e\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/dashscope/api_entities/http_request.py:286\u001B[0m, in \u001B[0;36mHttpRequest._handle_request\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 284\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 285\u001B[0m logger\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mRequest body: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m'\u001B[39m \u001B[38;5;241m%\u001B[39m obj)\n\u001B[0;32m--> 286\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43msession\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpost\u001B[49m\u001B[43m(\u001B[49m\u001B[43murl\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 287\u001B[0m \u001B[43m \u001B[49m\u001B[43mstream\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mstream\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 288\u001B[0m \u001B[43m \u001B[49m\u001B[43mjson\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mobj\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 289\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m{\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m}\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 290\u001B[0m \u001B[43m \u001B[49m\u001B[43mtimeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mtimeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 291\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mmethod \u001B[38;5;241m==\u001B[39m HTTPMethod\u001B[38;5;241m.\u001B[39mGET:\n\u001B[1;32m 292\u001B[0m response \u001B[38;5;241m=\u001B[39m session\u001B[38;5;241m.\u001B[39mget(url\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39murl,\n\u001B[1;32m 293\u001B[0m params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mdata\u001B[38;5;241m.\u001B[39mparameters,\n\u001B[1;32m 294\u001B[0m headers\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mheaders,\n\u001B[1;32m 295\u001B[0m timeout\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mtimeout)\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/requests/sessions.py:637\u001B[0m, in \u001B[0;36mSession.post\u001B[0;34m(self, url, data, json, **kwargs)\u001B[0m\n\u001B[1;32m 626\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mpost\u001B[39m(\u001B[38;5;28mself\u001B[39m, url, data\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, json\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[1;32m 627\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124mr\u001B[39m\u001B[38;5;124;03m\"\"\"Sends a POST request. Returns :class:`Response` object.\u001B[39;00m\n\u001B[1;32m 628\u001B[0m \n\u001B[1;32m 629\u001B[0m \u001B[38;5;124;03m :param url: URL for the new :class:`Request` object.\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 634\u001B[0m \u001B[38;5;124;03m :rtype: requests.Response\u001B[39;00m\n\u001B[1;32m 635\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[0;32m--> 637\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mPOST\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdata\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mdata\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mjson\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mjson\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/requests/sessions.py:589\u001B[0m, in \u001B[0;36mSession.request\u001B[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001B[0m\n\u001B[1;32m 584\u001B[0m send_kwargs \u001B[38;5;241m=\u001B[39m {\n\u001B[1;32m 585\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtimeout\u001B[39m\u001B[38;5;124m\"\u001B[39m: timeout,\n\u001B[1;32m 586\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mallow_redirects\u001B[39m\u001B[38;5;124m\"\u001B[39m: allow_redirects,\n\u001B[1;32m 587\u001B[0m }\n\u001B[1;32m 588\u001B[0m send_kwargs\u001B[38;5;241m.\u001B[39mupdate(settings)\n\u001B[0;32m--> 589\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprep\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43msend_kwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 591\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m resp\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/requests/sessions.py:703\u001B[0m, in \u001B[0;36mSession.send\u001B[0;34m(self, request, **kwargs)\u001B[0m\n\u001B[1;32m 700\u001B[0m start \u001B[38;5;241m=\u001B[39m preferred_clock()\n\u001B[1;32m 702\u001B[0m \u001B[38;5;66;03m# Send the request\u001B[39;00m\n\u001B[0;32m--> 703\u001B[0m r \u001B[38;5;241m=\u001B[39m \u001B[43madapter\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mrequest\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 705\u001B[0m \u001B[38;5;66;03m# Total elapsed time of the request (approximately)\u001B[39;00m\n\u001B[1;32m 706\u001B[0m elapsed \u001B[38;5;241m=\u001B[39m preferred_clock() \u001B[38;5;241m-\u001B[39m start\n",
"File \u001B[0;32m~/src/knightutils/.venv/lib/python3.10/site-packages/requests/adapters.py:675\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[1;32m 671\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m ProxyError(e, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[1;32m 673\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(e\u001B[38;5;241m.\u001B[39mreason, _SSLError):\n\u001B[1;32m 674\u001B[0m \u001B[38;5;66;03m# This branch is for urllib3 v1.22 and later.\u001B[39;00m\n\u001B[0;32m--> 675\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m SSLError(e, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[1;32m 677\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mConnectionError\u001B[39;00m(e, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[1;32m 679\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m ClosedPoolError \u001B[38;5;28;01mas\u001B[39;00m e:\n",
"\u001B[0;31mSSLError\u001B[0m: HTTPSConnectionPool(host='dashscope.aliyuncs.com', port=443): Max retries exceeded with url: /api/v1/services/aigc/text-generation/generation (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)')))"
]
}
],
"execution_count": 2
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e8170348d3bad72",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,41 @@
from llama_index.core.base.llms.types import ChatMessage
from llama_index.llms.dashscope import DashScope
import asyncio
llm = DashScope(model_name="qwen-max") # 设置检索引擎生成回答时调用的大模型。
def test1():
response = llm.complete("William Shakespeare is ")
print(response)
async def test2():
response = await llm.acomplete("William Shakespeare is ")
print(response)
def test3():
response = llm.stream_complete("William Shakespeare is ")
for chunk in response:
print(chunk)
def test4():
handle = llm.stream_complete("William Shakespeare is ")
for token in handle:
print(token.delta, end="", flush=True)
def test5():
messages = [
ChatMessage(role="system", content="You are a helpful assistant."),
ChatMessage(role="user", content="Tell me a joke."),
]
chat_response = llm.chat(messages)
print(chat_response)
if __name__ == '__main__':
# test1()
# asyncio.run(test2())
# test3()
# test4()
test5()

View File

@@ -0,0 +1,61 @@
{
"cells": [
{
"cell_type": "code",
"id": "48072a19c44a9164",
"metadata": {
"ExecuteTime": {
"end_time": "2025-08-27T16:02:46.279589Z",
"start_time": "2025-08-27T16:02:46.277036Z"
}
},
"source": [
"print(\"hello\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello\n"
]
}
],
"execution_count": 2
},
{
"cell_type": "code",
"execution_count": null,
"id": "initial_id",
"metadata": {
"collapsed": true,
"jupyter": {
"is_executing": true
}
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

16
test/mcp/math_server.py Normal file
View File

@@ -0,0 +1,16 @@
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Math")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
@mcp.tool()
def multiply(a: int, b: int) -> int:
"""Multiply two numbers"""
return a * b
if __name__ == "__main__":
mcp.run(transport="stdio")

77
test/qwenagent/start.py Normal file
View File

@@ -0,0 +1,77 @@
import pprint
import urllib.parse
import json5
from qwen_agent.agents import Assistant
from qwen_agent.tools.base import BaseTool, register_tool
from qwen_agent.utils.output_beautify import typewriter_print
# Step 1 (Optional): Add a custom tool named `my_image_gen`.
@register_tool('my_image_gen')
class MyImageGen(BaseTool):
# The `description` tells the agent the functionality of this tool.
description = 'AI painting (image generation) service, input text description, and return the image URL drawn based on text information.'
# The `parameters` tell the agent what input parameters the tool has.
parameters = [{
'name': 'prompt',
'type': 'string',
'description': 'Detailed description of the desired image content, in English',
'required': True
}]
def call(self, params: str, **kwargs) -> str:
# `params` are the arguments generated by the LLM agent.
prompt = json5.loads(params)['prompt']
prompt = urllib.parse.quote(prompt)
return json5.dumps(
{'image_url': f'https://image.pollinations.ai/prompt/{prompt}'},
ensure_ascii=False)
# Step 2: Configure the LLM you are using.
llm_cfg = {
# Use the model service provided by DashScope:
'model': 'qwen-max-latest',
'model_type': 'qwen_dashscope',
# 'api_key': 'YOUR_DASHSCOPE_API_KEY',
# It will use the `DASHSCOPE_API_KEY' environment variable if 'api_key' is not set here.
# Use a model service compatible with the OpenAI API, such as vLLM or Ollama:
# 'model': 'Qwen2.5-7B-Instruct',
# 'model_server': 'http://localhost:8000/v1', # base_url, also known as api_base
# 'api_key': 'EMPTY',
# (Optional) LLM hyperparameters for generation:
'generate_cfg': {
'top_p': 0.8
}
}
# Step 3: Create an agent. Here we use the `Assistant` agent as an example, which is capable of using tools and reading files.
system_instruction = '''After receiving the user's request, you should:
- first draw an image and obtain the image url,
- then run code `request.get(image_url)` to download the image,
- and finally select an image operation from the given document to process the image.
Please show the image using `plt.show()`.'''
tools = ['my_image_gen', 'code_interpreter'] # `code_interpreter` is a built-in tool for executing code.
files = ['./examples/resource/doc.pdf'] # Give the bot a PDF file to read.
bot = Assistant(llm=llm_cfg,
system_message=system_instruction,
function_list=tools,
files=files)
# Step 4: Run the agent as a chatbot.
messages = [] # This stores the chat history.
while True:
# For example, enter the query "draw a dog and rotate it 90 degrees".
query = input('\nuser query: ')
# Append the user query to the chat history.
messages.append({'role': 'user', 'content': query})
response = []
response_plain_text = ''
print('bot response:')
for response in bot.run(messages=messages):
# Streaming output.
response_plain_text = typewriter_print(response, response_plain_text)
# Append the bot responses to the chat history.
messages.extend(response)

View File

@@ -0,0 +1,34 @@
# 正确示例:显式类型注解
import os
from pydantic import BaseModel
class User(BaseModel):
id: int # 显式指定int类型
name: str # 显式指定str类型
is_active: bool = True # 带默认值的类型注解
# 错误示例:缺少类型注解
# class BadUser(BaseModel):
# id = 1 # 缺少类型注解Pydantic 2.9+将报错
# name = "John" # 缺少类型注解Pydantic 2.9+将报错
os.environ['app_port'] = '8888'
# 环境变量自动映射示例
from pydantic_settings import BaseSettings, SettingsConfigDict
class AppConfig(BaseSettings):
host: str = "localhost"
port: int = 8000
model_config = SettingsConfigDict(
env_prefix="APP_", # 环境变量前缀
case_sensitive=False # 不区分大小写
)
# 当环境变量存在APP_PORT=8080时
config = AppConfig()
print(config.port) # 输出: 8080 (而非默认的8000)