Skip to content

Commit 275deed

Browse files
committed
add tool agent app
1 parent ae6d8a2 commit 275deed

File tree

6 files changed

+214
-1
lines changed

6 files changed

+214
-1
lines changed

frontend/.env.sample

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ AZURE_OPENAI_API_KEY = "<aoai-api-key>"
77
AZURE_OPENAI_API_VERSION = "2024-05-01-preview"
88
AZURE_OPENAI_MODEL_WHISPER = "whisper"
99
AZURE_OPENAI_MODEL_CHAT = "gpt-4o"
10+
11+
# LangSmith
12+
LANGCHAIN_TRACING_V2 = "false" # set to "true" to enable tracing
13+
LANGCHAIN_API_KEY = "<api-key>"
14+
LANGCHAIN_ENDPOINT = "https://api.smith.langchain.com"
15+
LANGCHAIN_PROJECT = "default"

frontend/pages/tool_agent.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import logging
2+
from os import getenv
3+
4+
import streamlit as st
5+
from dotenv import load_dotenv
6+
from langchain.agents import AgentExecutor, create_tool_calling_agent
7+
from langchain.memory import ConversationBufferWindowMemory
8+
from langchain_community.callbacks import StreamlitCallbackHandler
9+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
10+
from langchain_core.runnables import RunnableConfig
11+
from langchain_openai import AzureChatOpenAI
12+
from tools.search_ddg import search_ddg
13+
14+
logger = logging.getLogger(__name__)
15+
load_dotenv()
16+
17+
18+
CUSTOM_SYSTEM_PROMPT = """
19+
あなたは、ユーザーのリクエストに基づいてインターネットで調べ物を行うアシスタントです。
20+
利用可能なツールを使用して、調査した情報を説明してください。
21+
既に知っていることだけに基づいて答えないでください。回答する前にできる限り検索を行ってください。
22+
(ユーザーが読むページを指定するなど、特別な場合は、検索する必要はありません。)
23+
24+
検索結果ページを見ただけでは情報があまりないと思われる場合は、次の2つのオプションを検討して試してみてください。
25+
26+
- 検索結果のリンクをクリックして、各ページのコンテンツにアクセスし、読んでみてください。
27+
- 1ページが長すぎる場合は、3回以上ページ送りしないでください(メモリの負荷がかかるため)。
28+
- 検索クエリを変更して、新しい検索を実行してください。
29+
- 検索する内容に応じて検索に利用する言語を適切に変更してください。
30+
- 例えば、プログラミング関連の質問については英語で検索するのがいいでしょう。
31+
32+
ユーザーは非常に忙しく、あなたほど自由ではありません。
33+
そのため、ユーザーの労力を節約するために、直接的な回答を提供してください。
34+
35+
=== 悪い回答の例 ===
36+
- これらのページを参照してください。
37+
- これらのページを参照してコードを書くことができます。
38+
- 次のページが役立つでしょう。
39+
40+
=== 良い回答の例 ===
41+
- これはサンプルコードです。 -- サンプルコードをここに --
42+
- あなたの質問の答えは -- 回答をここに --
43+
44+
回答の最後には、参照したページのURLを**必ず**記載してください。(これにより、ユーザーは回答を検証することができます)
45+
46+
ユーザーが使用している言語で回答するようにしてください。
47+
ユーザーが日本語で質問した場合は、日本語で回答してください。ユーザーがスペイン語で質問した場合は、スペイン語で回答してください。
48+
"""
49+
50+
51+
def init_page():
52+
st.set_page_config(page_title="Web Browsing Agent", page_icon="🤗")
53+
st.header("Web Browsing Agent 🤗")
54+
st.sidebar.title("Options")
55+
56+
57+
def init_messages():
58+
clear_button = st.sidebar.button("Clear Conversation", key="clear")
59+
if clear_button or "messages" not in st.session_state:
60+
st.session_state.messages = [{"role": "assistant", "content": "Please ask me any questions you may have."}]
61+
st.session_state["memory"] = ConversationBufferWindowMemory(
62+
return_messages=True, memory_key="chat_history", k=10
63+
)
64+
65+
66+
def create_agent():
67+
tools = [search_ddg]
68+
prompt = ChatPromptTemplate.from_messages(
69+
[
70+
("system", CUSTOM_SYSTEM_PROMPT),
71+
MessagesPlaceholder(variable_name="chat_history"),
72+
("user", "{input}"),
73+
MessagesPlaceholder(variable_name="agent_scratchpad"),
74+
]
75+
)
76+
llm = AzureChatOpenAI(
77+
temperature=0,
78+
api_key=getenv("AZURE_OPENAI_API_KEY"),
79+
api_version=getenv("AZURE_OPENAI_API_VERSION"),
80+
azure_endpoint=getenv("AZURE_OPENAI_ENDPOINT"),
81+
model=getenv("AZURE_OPENAI_MODEL_CHAT"),
82+
)
83+
agent = create_tool_calling_agent(llm, tools, prompt)
84+
return AgentExecutor(
85+
agent=agent,
86+
tools=tools,
87+
verbose=True,
88+
memory=st.session_state["memory"],
89+
)
90+
91+
92+
def main():
93+
init_page()
94+
init_messages()
95+
web_browsing_agent = create_agent()
96+
97+
for msg in st.session_state["memory"].chat_memory.messages:
98+
st.chat_message(msg.type).write(msg.content)
99+
100+
if prompt := st.chat_input(placeholder="Type your question here..."):
101+
st.chat_message("user").write(prompt)
102+
103+
with st.chat_message("assistant"):
104+
st_cb = StreamlitCallbackHandler(st.container(), expand_new_thoughts=True)
105+
response = web_browsing_agent.invoke(
106+
{"input": prompt},
107+
config=RunnableConfig({"callbacks": [st_cb]}),
108+
)
109+
st.write(response["output"])
110+
111+
112+
if __name__ == "__main__":
113+
main()

frontend/tools/__init__.py

Whitespace-only changes.

frontend/tools/search_ddg.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# GitHub: https://github.com/naotaka1128/llm_app_codes/chapter_009/tools/search_ddg.py
2+
3+
from itertools import islice
4+
5+
from duckduckgo_search import DDGS
6+
from langchain_core.pydantic_v1 import BaseModel, Field
7+
from langchain_core.tools import tool
8+
9+
"""
10+
Sample Response of DuckDuckGo python library
11+
--------------------------------------------
12+
[
13+
{
14+
'title': '日程・結果|Fifa 女子ワールドカップ オーストラリア&ニュージーランド 2023|なでしこジャパン|日本代表|Jfa|日本サッカー協会',
15+
'href': 'https://www.jfa.jp/nadeshikojapan/womensworldcup2023/schedule_result/',
16+
'body': '日程・結果|FIFA 女子ワールドカップ オーストラリア&ニュージーランド 2023|なでしこジャパン|日本代表|JFA|日本サッカー協会. FIFA 女子ワールドカップ. オーストラリア&ニュージーランド 2023.'
17+
}, ...
18+
]
19+
""" # noqa: E501
20+
21+
22+
class SearchDDGInput(BaseModel):
23+
query: str = Field(description="Type the keyword you want to search.")
24+
25+
26+
@tool(args_schema=SearchDDGInput)
27+
def search_ddg(query, max_result_num=5):
28+
"""
29+
DuckDuckGo検索を実行するためのツールです。
30+
検索したいキーワードを入力して使用してください。
31+
検索結果の各ページのタイトル、スニペット(説明文)、URLが返されます。
32+
このツールから得られる情報は非常に簡素化されており、時には古い情報の場合もあります。
33+
34+
必要な情報が見つからない場合は、必ず `WEB Page Fetcher` ツールを使用して各ページの内容を確認してください。
35+
文脈に応じて最も適切な言語を使用してください(ユーザーの言語と同じである必要はありません)。
36+
例えば、プログラミング関連の質問では、英語で検索するのが最適です。
37+
38+
Returns
39+
-------
40+
List[Dict[str, str]]:
41+
- title
42+
- snippet
43+
- url
44+
"""
45+
res = DDGS().text(
46+
query,
47+
region="wt-wt",
48+
safesearch="off",
49+
backend="lite",
50+
)
51+
return [
52+
{"title": r.get("title", ""), "snippet": r.get("body", ""), "url": r.get("href", "")}
53+
for r in islice(res, max_result_num)
54+
]

poetry.lock

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ langchain-openai = "^0.1.19"
6161
langchain-community = "^0.2.10"
6262
youtube-transcript-api = "^0.6.2"
6363
pytube = "^15.0.0"
64+
duckduckgo-search = "^6.2.3"
6465

6566

6667
[tool.poetry.group.azure-functions.dependencies]

0 commit comments

Comments
 (0)