Skip to content

Commit 5c7a5b4

Browse files
committed
feat: support search knowledgebase based on user's profile
1 parent 06cb7fe commit 5c7a5b4

File tree

4 files changed

+97
-76
lines changed

4 files changed

+97
-76
lines changed

veadk/knowledgebase/knowledgebase.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class KnowledgeBase(BaseModel):
108108

109109
enable_profile: bool = False
110110

111+
query_with_user_profile: bool = False
112+
111113
def model_post_init(self, __context: Any) -> None:
112114
if isinstance(self.backend, BaseKnowledgebaseBackend):
113115
self._backend = self.backend
@@ -134,6 +136,11 @@ def model_post_init(self, __context: Any) -> None:
134136
f"Initialized knowledgebase with backend {self._backend.__class__.__name__}"
135137
)
136138

139+
if self.query_with_user_profile:
140+
logger.info(
141+
"Enable user profile querying for knowledgebase. You *must* use Viking Memory backend to enjoy this feature."
142+
)
143+
137144
def add_from_directory(self, directory: str, **kwargs) -> bool:
138145
"""Add knowledge from file path to knowledgebase.
139146

veadk/memory/long_term_memory.py

Lines changed: 10 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -100,68 +100,6 @@ class LongTermMemory(BaseMemoryService, BaseModel):
100100
101101
Notes:
102102
Please ensure that you have set the embedding-related configurations in environment variables.
103-
104-
Examples:
105-
### Simple long-term memory
106-
107-
Once create a long-term memory withou any arguments, all configurations are come from **environment variables**.
108-
109-
```python
110-
import asyncio
111-
112-
from veadk import Agent, Runner
113-
from veadk.memory.long_term_memory import LongTermMemory
114-
from veadk.memory.short_term_memory import ShortTermMemory
115-
116-
app_name = "veadk_playground_app"
117-
user_id = "veadk_playground_user"
118-
119-
long_term_memory = LongTermMemory(backend="local", app_name=app_name)
120-
121-
agent = Agent(long_term_memory=long_term_memory)
122-
123-
runner = Runner(
124-
agent=agent,
125-
app_name=app_name,
126-
user_id=user_id,
127-
short_term_memory=ShortTermMemory(),
128-
)
129-
130-
# ===== add memory =====
131-
session_id = "veadk_playground_session"
132-
teaching_prompt = "I brought an ice-cream last week."
133-
134-
asyncio.run(runner.run(messages=teaching_prompt, session_id=session_id))
135-
asyncio.run(
136-
runner.save_session_to_long_term_memory(session_id=session_id)
137-
) # save session to long-term memory
138-
139-
140-
# ===== check memory =====
141-
session_id = "veadk_playground_session_2" # use a new session
142-
student_prompt = "What I brought last week?"
143-
144-
response = asyncio.run(runner.run(messages=student_prompt, session_id=session_id))
145-
146-
print(response)
147-
```
148-
149-
### Create with a backend instance
150-
151-
```python
152-
from veadk.memory.long_term_memory import LongTermMemory
153-
from veadk.memory.long_term_memory.backends import LongTermMemory
154-
155-
long_term_memory = LongTermMemory(backend=...)
156-
```
157-
158-
### Create with backend configurations
159-
160-
```python
161-
from veadk.memory.long_term_memory import LongTermMemory
162-
163-
long_term_memory = LongTermMemory(backend="", backend_config={})
164-
```
165103
"""
166104

167105
backend: Union[
@@ -313,20 +251,6 @@ async def search_memory(
313251
SearchMemoryResponse:
314252
An object containing a list of `MemoryEntry` items representing
315253
the retrieved memory snippets relevant to the query.
316-
317-
Examples:
318-
```python
319-
response = await memory_service.search_memory(
320-
app_name="chat_app",
321-
user_id="user_123",
322-
query="favorite programming language"
323-
)
324-
325-
for memory in response.memories:
326-
print(memory.content.parts[0].text)
327-
# Output:
328-
# User likes Python and TypeScript for backend development.
329-
```
330254
"""
331255
logger.info(f"Search memory with query={query}")
332256

@@ -369,3 +293,13 @@ async def search_memory(
369293
f"Return {len(memory_events)} memory events for query: {query} index={self.index} user_id={user_id}"
370294
)
371295
return SearchMemoryResponse(memories=memory_events)
296+
297+
def get_user_profile(self, user_id: str) -> str:
298+
logger.info(f"Get user profile for user_id={user_id}")
299+
if self.backend == "viking":
300+
return self._backend.get_user_profile(user_id=user_id) # type: ignore
301+
else:
302+
logger.error(
303+
f"Long term memory backend {self.backend} does not support get user profile. Return empty string."
304+
)
305+
return ""

veadk/memory/long_term_memory_backends/vikingdb_memory_backend.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,58 @@ def search_memory(
224224
for r in result
225225
]
226226
return []
227+
228+
def get_user_profile(self, user_id: str) -> str:
229+
from veadk.utils.volcengine_sign import ve_request
230+
231+
response: dict = self._get_client().get_collection(
232+
collection_name=self.index, project=self.volcengine_project
233+
)
234+
235+
mem_id = response["Result"]["ResourceId"]
236+
logger.info(
237+
f"Get user profile for user_id={user_id} from Viking Memory with mem_id={mem_id}"
238+
)
239+
240+
ak = ""
241+
sk = ""
242+
sts_token = ""
243+
if self.volcengine_access_key and self.volcengine_secret_key:
244+
ak = self.volcengine_access_key
245+
sk = self.volcengine_secret_key
246+
sts_token = self.session_token
247+
else:
248+
cred = get_credential_from_vefaas_iam()
249+
ak = cred.access_key_id
250+
sk = cred.secret_access_key
251+
sts_token = cred.session_token
252+
253+
response = ve_request(
254+
request_body={
255+
"filter": {
256+
"user_id": [user_id],
257+
"memory_category": 1,
258+
},
259+
"limit": 5000,
260+
"resource_id": mem_id,
261+
},
262+
action="MemorySearch",
263+
ak=ak,
264+
sk=sk,
265+
header={"X-Security-Token": sts_token},
266+
service="vikingdb",
267+
version="2025-06-09",
268+
region=self.region,
269+
host="open.volcengineapi.com",
270+
)
271+
272+
try:
273+
logger.debug(
274+
f"Response from VikingDB: {response}, user_profile: {response['data']['result_list'][0]['memory_info']['user_profile']}"
275+
)
276+
return response["data"]["result_list"][0]["memory_info"]["user_profile"]
277+
except (KeyError, IndexError):
278+
logger.error(
279+
f"Failed to get user profile for user_id={user_id} mem_id={mem_id}: {response}"
280+
)
281+
return ""

veadk/tools/builtin_tools/load_knowledgebase.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,31 @@ async def process_llm_request(
124124
]
125125
)
126126

127+
if self.knowledgebase.query_with_user_profile:
128+
from veadk import Agent
129+
130+
agent = tool_context._invocation_context.agent
131+
if not isinstance(agent, Agent) or not agent.long_term_memory:
132+
logger.error(
133+
"Agent in tool context is not an instance of veadk.Agent or long term memory is not set in agent attribution. Cannot load user profile."
134+
)
135+
return
136+
137+
user_profile = agent.long_term_memory.get_user_profile(tool_context.user_id)
138+
139+
if user_profile:
140+
llm_request.append_instructions(
141+
[
142+
f"""
143+
Please generate the knowledgebase queries based on the user profile (description) at the same time. For example, for a query `quick sort algorithm`, you should generate `quick sort algorithm for python` if the user is a python developer, or `quick sort algorithm friendly introduction` if the user is a beginner.
144+
145+
The user profile is :
146+
147+
{user_profile}
148+
"""
149+
]
150+
)
151+
127152
async def load_knowledgebase(
128153
self, query: str, tool_context: ToolContext
129154
) -> LoadKnowledgebaseResponse:

0 commit comments

Comments
 (0)