Skip to content

Commit 6107b38

Browse files
authored
Merge pull request #578 from jupyter-naas/510-use-langchain---chatperplexity-in-perplexity-agent
feat: use langchain chatperplexity in perplexity agent
2 parents 193ea5e + 45e9343 commit 6107b38

8 files changed

Lines changed: 74 additions & 189 deletions

File tree

lib/abi/services/agent/Agent.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,9 @@ def __init__(
286286

287287
# TODO: Make sure the Agent does not call the version without tools.
288288
self._chat_model = chat_model
289-
self._chat_model_with_tools = chat_model.bind_tools(self._structured_tools)
289+
self._chat_model_with_tools = chat_model
290+
if self._tools:
291+
self._chat_model_with_tools = chat_model.bind_tools(self._structured_tools)
290292

291293
# Use provided memory or create based on environment
292294
if memory is None:
@@ -376,7 +378,7 @@ def build_graph(self, patcher: Optional[Callable] = None):
376378
graph = StateGraph(MessagesState)
377379
graph.add_node(self.call_model)
378380
graph.add_edge(START, "call_model")
379-
381+
380382
graph.add_node(self.call_tools)
381383
# This is not needed because the call_tools is generating the proper Command to go to the right node after each tool call.
382384
# graph.add_edge("call_tools", "call_model")

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ dependencies = [
6363
"psycopg[binary,pool]>=3.2.9",
6464
"langgraph-checkpoint-postgres>=2.0.23",
6565
"mypy>=1.17.1",
66+
"langchain-perplexity>=0.1.2",
6667
]
6768

6869
[project.scripts]

src/__modules__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,17 @@ def analyze_module_dependencies(module_paths: List[str]) -> Dict[str, Set[str]]:
4040
if isinstance(node, ast.Call):
4141
if isinstance(node.func, ast.Name) and node.func.id == 'get_modules':
4242
get_modules_found = True
43-
logger.debug(f"Found get_modules() call in {py_file}")
4443
break
4544
elif isinstance(node.func, ast.Attribute) and node.func.attr == 'get_modules':
4645
get_modules_found = True
47-
logger.debug(f"Found get_modules() call in {py_file}")
4846
break
4947

5048
# If get_modules() is found, this module depends on ALL other modules
5149
if get_modules_found:
5250
for other_module in module_paths:
5351
if other_module != module_path:
5452
dependencies[module_path].add(other_module)
55-
logger.info(f"Module {module_path} calls get_modules() - depends on ALL other modules")
53+
logger.debug(f"Module {module_path} depends on ALL other modules")
5654
else:
5755
# Regular dependency analysis for import statements
5856
for node in ast.walk(tree):
Lines changed: 38 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,66 @@
1-
from abi.services.agent.IntentAgent import (
2-
IntentAgent,
3-
Intent,
4-
IntentType,
1+
from abi.services.agent.Agent import (
2+
Agent,
53
AgentConfiguration,
64
AgentSharedState,
5+
MemorySaver,
76
)
8-
from abi.services.agent.Agent import Agent
9-
from fastapi import APIRouter
10-
from src.core.modules.perplexity.models.perplexity_gpt_4o import model
117
from typing import Optional
12-
from enum import Enum
13-
from abi import logger
8+
from src.core.modules.perplexity.models.sonar_pro import model
149

15-
AVATAR_URL = "https://naasai-public.s3.eu-west-3.amazonaws.com/abi/assets/perplexity.png"
1610
NAME = "Perplexity"
17-
TYPE = "core"
18-
SLUG = "perplexity"
1911
DESCRIPTION = "Perplexity Agent that provides real-time answers to any question on the web using Perplexity AI."
20-
MODEL = "perplexity-gpt-4o"
21-
SYSTEM_PROMPT = """
22-
Role:
23-
You are Perplexity, a researcher agent with access to Perplexity AI search engine.
24-
25-
Objective:
26-
Provide accurate and comprehensive information to user inquiries using your web search capabilities.
27-
28-
Context:
29-
You will receive prompts from users but also from a supervisor agent named 'abi' that already handle the conversation with the user.
30-
When users say things like "ask perplexity", "parler à perplexity", "I want to talk to perplexity", or similar phrases referring to YOU:
31-
- Recognize that YOU ARE Perplexity - don't try to "connect" them to Perplexity
32-
- Respond directly as Perplexity without any delegation confusion
33-
- Simply acknowledge and proceed to help them directly
34-
- Never say "I cannot connect you to Perplexity" - you ARE Perplexity!
35-
36-
Tasks:
37-
- Answer the user's question
38-
- If you don't know the answer, you must ask more information to the user or propose to use differents agents to answer the question.
39-
40-
Tools:
41-
- current_datetime: Get the current datetime in Paris timezone.
42-
- ask_question: Ask a question to Perplexity AI
43-
44-
Operating Guidelines:
45-
1. Get the date and time using current_datetime tool and add it to user's question
46-
For example:
47-
"le gagnant de la dernière ligue des champions masculin" -> "Current datetime: 2025-06-25 10:00:00 : le gagnant de la dernière ligue des champions masculin"
48-
2. Perform the search using Perplexity AI tool: ask_question
49-
3. Present information as found in search results
50-
51-
Constraints:
52-
- Must follow the operating guidelines from any prompts you receive
53-
- NEVER use your internal knowledge base to answer questions
54-
- Try to find at least 1 source in the response which is not a link to the Perplexity page.
55-
- Must display sources full URL
56-
- Must format sources as at the end of the response after 2 blank lines:
57-
```
58-
**Sources:**
59-
- [Source Name](source_url)
60-
```
61-
62-
Examples:
63-
```
64-
**Sources:**
65-
- [Les echos](https://www.lesechos.fr/entreprises-et-marches/actualites/2025-06-25/)
66-
- [Le Monde](https://www.lemonde.fr/economie/article
67-
- [Le Parisien](https://www.leparisien.fr/economie/article
68-
```
69-
"""
70-
TEMPERATURE = 0
71-
DATE = True
72-
INSTRUCTIONS_TYPE = "system"
73-
ONTOLOGY = True
12+
AVATAR_URL = "https://naasai-public.s3.eu-west-3.amazonaws.com/abi/assets/perplexity.png"
7413
SUGGESTIONS: list = []
7514

7615
def create_agent(
7716
agent_shared_state: Optional[AgentSharedState] = None,
7817
agent_configuration: Optional[AgentConfiguration] = None
79-
) -> Optional[IntentAgent]:
80-
# Check if model is available
81-
if model is None:
82-
logger.error("Perplexity model not available - missing OpenAI API key and Perplexity API key")
83-
return None
84-
18+
) -> Agent:
19+
# System prompt
20+
SYSTEM_PROMPT = """
21+
Role:
22+
You are Perplexity, an advanced AI research agent powered by the Perplexity AI search engine.
23+
You excel at real-time information gathering, fact-checking, and providing up-to-date insights across all fields of knowledge.
24+
25+
Objective:
26+
- Deliver comprehensive, well-researched answers by leveraging real-time web search capabilities
27+
- Synthesize information from multiple reliable sources to provide balanced perspectives
28+
- Present complex topics in a clear, accessible manner while maintaining accuracy
29+
- Proactively fact-check information and acknowledge any limitations in available data
30+
- Include relevant context and background information when beneficial to understanding
31+
32+
Constraints:
33+
- You maintain a professional yet approachable tone, always striving for accuracy and clarity in your responses.
34+
- Only include source references when you have actual URLs to cite
35+
- When citing sources, place them at the end of your response after two blank lines
36+
- Format sources exactly as shown in the example below:
37+
38+
Examples:
39+
```
40+
**Sources:**
41+
- [1](https://www.lesechos.fr/entreprises-et-marches/actualites/2025-06-25/)
42+
- [2](https://www.lemonde.fr/economie/article)
43+
- [3](https://www.leparisien.fr/economie/article)
44+
```
45+
"""
8546
# Set configuration
8647
if agent_configuration is None:
8748
agent_configuration = AgentConfiguration(
8849
system_prompt=SYSTEM_PROMPT,
8950
)
9051
if agent_shared_state is None:
9152
agent_shared_state = AgentSharedState(thread_id="0")
92-
93-
94-
# Init
95-
from langchain_core.tools import Tool
96-
from typing import List, Union
97-
98-
tools: List[Union[Tool, Agent]] = []
99-
100-
from src import secret
101-
from src.core.modules.perplexity.integrations import PerplexityIntegration
102-
from src.core.modules.perplexity.integrations.PerplexityIntegration import PerplexityIntegrationConfiguration
103-
104-
perplexity_api_key = secret.get('PERPLEXITY_API_KEY')
105-
if perplexity_api_key is not None:
106-
perplexity_integration_configuration = PerplexityIntegrationConfiguration(
107-
api_key=perplexity_api_key
108-
)
109-
tools += PerplexityIntegration.as_tools(perplexity_integration_configuration)
110-
else:
111-
logger.error("Perplexity model not available - missing Perplexity API key")
112-
return None
113-
114-
from datetime import datetime
115-
from zoneinfo import ZoneInfo
116-
from langchain_core.tools import StructuredTool
117-
from pydantic import BaseModel
118-
119-
class EmptySchema(BaseModel):
120-
pass
121-
122-
current_datetime_tool = StructuredTool(
123-
name="current_datetime",
124-
description="Get the current datetime in Paris timezone.",
125-
func=lambda : datetime.now(tz=ZoneInfo('Europe/Paris')),
126-
args_schema=EmptySchema
127-
)
128-
129-
from typing import cast
130-
tools += [cast(Tool, current_datetime_tool)]
131-
132-
intents: list = [
133-
Intent(
134-
intent_value="what is your name",
135-
intent_type=IntentType.RAW,
136-
intent_target="I am Perplexity, an AI research assistant that provides real-time answers using web search capabilities.",
137-
),
138-
Intent(
139-
intent_value="what can you do",
140-
intent_type=IntentType.RAW,
141-
intent_target="I can search the web in real-time, provide up-to-date information, research any topic, and answer questions using the latest information from the internet.",
142-
),
143-
]
14453

14554
return PerplexityAgent(
14655
name=NAME,
14756
description=DESCRIPTION,
148-
chat_model=model.model,
149-
tools=tools,
57+
chat_model=model,
58+
tools=[],
15059
agents=[],
151-
intents=intents,
15260
state=agent_shared_state,
15361
configuration=agent_configuration,
154-
memory=None
62+
memory=MemorySaver()
15563
)
15664

157-
class PerplexityAgent(IntentAgent):
158-
def as_api(
159-
self,
160-
router: APIRouter,
161-
route_name: str = NAME,
162-
name: str = NAME.replace("_", " "),
163-
description: str = "API endpoints to call the Perplexity agent completion.",
164-
description_stream: str = "API endpoints to call the Perplexity agent stream completion.",
165-
tags: Optional[list[str | Enum]] = None,
166-
) -> None:
167-
if tags is None:
168-
tags = []
169-
return super().as_api(
170-
router, route_name, name, description, description_stream, tags
171-
)
65+
class PerplexityAgent(Agent):
66+
pass
Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
11
import pytest
22

3-
from src.core.modules.perplexity.agents.PerplexityAgent import create_agent
4-
53
@pytest.fixture
64
def agent():
5+
from src.core.modules.perplexity.agents.PerplexityAgent import create_agent
76
return create_agent()
87

98
def test_agent_name(agent):
10-
result = agent.invoke("what is your name")
9+
result = agent.invoke("What is your name?")
1110

1211
assert result is not None, result
1312
assert "Perplexity" in result, result
1413

15-
def test_search_news(agent):
16-
result = agent.invoke("Which team won the last men's Champions League?")
17-
18-
assert result is not None, result
19-
assert "Paris Saint-Germain" in result, result
20-
2114
def test_search_news_with_datetime(agent):
2215
from datetime import datetime
2316

2417
result = agent.invoke("What are the news of the day? Start by: 'As of today the date is YYYY-MM-DD.'")
2518

2619
assert result is not None, result
27-
assert datetime.now().strftime("%Y-%m-%d") in result, result
20+
assert datetime.now().strftime("%Y-%m-%d") in result, result
21+
assert "sources" in result.lower(), result

src/core/modules/perplexity/models/perplexity_gpt_4o.py

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from langchain_perplexity import ChatPerplexity
2+
from src import secret
3+
from pydantic import SecretStr
4+
from abi import logger
5+
6+
perplexity_api_key = secret.get("PERPLEXITY_API_KEY")
7+
model = ChatPerplexity(
8+
model="sonar",
9+
temperature=0,
10+
api_key=SecretStr(perplexity_api_key),
11+
timeout=120
12+
)
13+
logger.debug("✅ Perplexity GPT-4o model loaded successfully via OpenAI")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from langchain_perplexity import ChatPerplexity
2+
from src import secret
3+
from pydantic import SecretStr
4+
from abi import logger
5+
6+
perplexity_api_key = secret.get("PERPLEXITY_API_KEY")
7+
model = ChatPerplexity(
8+
model="sonar-pro",
9+
temperature=0,
10+
api_key=SecretStr(perplexity_api_key),
11+
timeout=120
12+
)
13+
logger.debug("✅ Perplexity GPT-4o model loaded successfully via OpenAI")

0 commit comments

Comments
 (0)